SlideShare a Scribd company logo
1 of 202
Download to read offline
Dev Django
2018 KOREA
START
Django의 배신

주니어 개발자의 Django 삽질기

김은향
DJANGO의	배신	
주니어	개발자의	Django	삽질기
또		
삽질하냐
각본,	연출:	
김은향
1. 장고와 나
DevDjango Korea목차
목차
2. ORM뒤에 숨겨진

블랙홀
3. 트랜잭션 적용하다 

celery에게 뒷통수 맞다!
4. 헌집 줄게, 새집 다오
5. 삽질기는

계속된다
제1장.	장고와	나
1. 장고와 나
Who am I?
개발한지 이제 1년 된 뽀시래기 주니어 개발자

스스로 개발자라는게 아직도 신기함

만나는 개발자 분들마다 존경스러워요..!

내가 DevDjango에서 발표라니..!(쏘리질러!)
DevDjango Korea
개발은.. 어쩌다 시작하셨나요?
디자인 하다가 화나서!!!!!!!!!(분노)
1. 장고와 나 DevDjango Korea
이런..어쩌다 그런..
개발자님..	1픽셀만	옮겨주세요..		
아..아니	그	테두리좀	없..	
익스플로러에서	왜	이렇게	보여요..	
아..아니..그게아니라..	쭈글쭈글
1. 장고와 나1. 장고와 나 DevDjango Korea
그래서 어떤 선택을..?
나도 한 때 (프포자)공대생이었는데!!!!

까짓거 내가 개발해보겠어!!!
1. 장고와 나 DevDjango Korea
산 넘어 더 큰 산
Dd
Java산 JSP산 Servlet산 Spring산
아..나는	뼛속까지	문과생..프포자..	
게시판	하나	만드는	게	이렇게	힘들다니...
1. 장고와 나 DevDjango Korea
내 눈!!!!!!
1. 장고와 나 DevDjango Korea
JAVA가 문제가 아니에요..
코드만 보면 급격히 떨어지는 내 인내심이 문제
1. 장고와 나 DevDjango Korea
그러다 우연히 만나게 된 그 이름하여..!
1. 장고와 나 DevDjango Korea
엄청나게 친절한 django girls 튜토리얼
이거해본다고

뭐가 나오겠어..

따라하긴 쉽네..한글로 옴청 친절하고..
1. 장고와 나 DevDjango Korea
!!!
뭐지..	
이	간지나는..블로그는..?	
세상에나 내가 지금 블로그 만든겨?!
1. 장고와 나 DevDjango Korea
Django, 너는 내 운명
쉽고 재밌는데 게다가 python..!

자, Django 개발자가 되어 봅시다!
1. 장고와 나 DevDjango Korea
Django하려 하면 이런 일들이?!1
운
간절함
스터디에 합격하셨습니다!
1. 장고와 나 DevDjango Korea
Django하려 하면 이런 일들이?!2
운
인복
Django 프로젝트 팀에 합류했습니다!!
1. 장고와 나 DevDjango Korea
Django하려 하면 이런 일들이?!3
Django 인턴개발자로 취업했습니다!!

Django 원주민 팀장님을 만났습니다!!!
운
인복
1. 장고와 나
장고장고
DevDjango Korea
그리하여...


주니어 백엔드 개발자가 되었습니다!
근자감
살어리 살어리랏다 장고랑 살어리랏다~~
1. 장고와 나 DevDjango Korea
시간은 흘러흘러~
약 1년 후...
1. 장고와 나 DevDjango Korea
Django에게 배신당하다..!
Django…	누가	쉽댔냐....	
과거의	나..원망한다..1. 장고와 나 DevDjango Korea
Django로 개발을 하면 할수록..
나는 정말 근자감 천재였구나..!
컴퓨터도 몰라..

파이썬도 몰라..

네트워크도 몰라..

그런데 Django도 몰라..!

1. 장고와 나 DevDjango Korea
그래서 제 사연은요..
정말	(쉽다고,	재밌다고)	철썩같이		
믿었는데...	
세	번이나	배신당했어요...	
먼저	ORM..그	녀석이..하...	
…
1. 장고와 나
ps. 이제 막 Django하시는 개발자분들도 배신당하지 말아요 함께!!
DevDjango Korea
제2장.		
ORM뒤에	숨겨진	블랙홀!
2. ORM뒤에 

숨겨진 블랙홀
Django 개발자가 된 lv1 야도란
ORM을 만나서 진화-@@@!
쿼리를 낚다가..
DevDjango Korea
SQL 그게 뭐야? :)
SELECT
FROM
JOIN
GROUB BY
WHEN
ON
WHERE
INSERT
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
얍!
얍!
얍!
OH! ORM 찬양! OH!
포스트 다 가져오기

포스트 1개 가져오기

내가 쓴 포스트 가져오기
Post.objects.all()

Post.objects.get(id=1)

Post.objects.filter(username=“hyang”)
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
실제 상황 1
USER:
2. ORM뒤에 

숨겨진 블랙홀
저희 머신러닝 모델의 여러 버전들마다 실행된 것들에서
8월 1일에서 8월 20일까지 실행된 것 들 중
error없이 실행된 active한 것들만 모아서
응답시간의 평균 값, 최대값
그리고 모델에 설정한 스레숄드 값보다 빠르게 응답한 개수를
보여주는 화려한 대시보드 만들어주세요 ^^
“
“
DevDjango Korea
?????????????
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
SQL 강제 공부 돌입
SELECT
FROM
JOIN
GROUB BY
WHEN
ON
WHERE
얘네 가져올꺼야 이럴 때만
얘네들만 묶어서
저기서부터 가져와서
교집합 차집합 합집합..
이런 것들만
2. ORM뒤에 

숨겨진 블랙홀
잘못했어요..
살려주세요..
DevDjango Korea
드디어 쿼리문 완성!!
SELECT
AVG(run.response_time) as "avg_response_time"
, Max(run.response_time) as "max_response_time"
, SUM(1) as num_runs
, SUM(case when run.response_time > ml_model.slow_run_threshold_in_milliseconds then 1
else 0 end) as num_fast_runs
FROM run
JOIN version on version.id = run.version_id
JOIN ml_model ml_model on run. ml_model_id = ml_model.id
WHERE run.requested_at >= '2018-08-01'::timestamp with time zone AND run.requested_at <
'2018-08-20'::timestamp with time zone
AND run.is_active = True
AND version.id in (versions_ids)
2. ORM뒤에 

숨겨진 블랙홀
짜잔!
DevDjango Korea
쿼리도 쓰고 대단해!!
2. ORM뒤에 

숨겨진 블랙홀
근데..		
어떻게	썼더라..
DevDjango Korea
머리에 쥐나요...
도와줘요..	ORM...	
착하게	개발할게요...	
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
ORM 응급실
ORM에대한 희망을 잃지 말아요~

도큐먼트에는 다 있으니까~
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
필요한 데이터 뽑기!
2. ORM뒤에 

숨겨진 블랙홀
저희 머신러닝 모델의 여러 버전마다 실행된 것들에서
8월 1일에서 8월 20일까지 실행된 것 들 중
error없이 실행된 active한 것들만 모아서
응답시간의 평균 값, 최대값
그리고 저희 모델에 설정한 스레숄드 값보다 빠르게 응답한 개수를
보여주는 화려한 대쉬보드 만들어주세요 ^^
저 조건들 다 filter에 넣고 한 번에 가져올 수 있으면 좋겠다..
“
“
DevDjango Korea
가져올 수 있음!!
2. ORM뒤에 

숨겨진 블랙홀
run_qs = Run.objects.filter(
version__id__in=version_ids,
ml_model__id__in=version_ids,
is_active=True,
requested_at__range=(start_date, end_date)
)
Filter에 ForeignKey도 조건으로 막 넣고! 

list에 포함되는지는 in! 범위는 range!
DevDjango Korea
그렇게 모은 쿼리셋!
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
표로 보면 이렇게
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
평균? 최대값?
2. ORM뒤에 

숨겨진 블랙홀
저희 머신러닝 모델의 여러 버전마다 실행된 것들에서
8월 1일에서 8월 20일까지 실행된 것 들 중
error없이 실행된 active한 것들만 모아서
응답시간의 평균 값, 최대값
그리고 저희 모델에 설정한 스레숄드 값보다 빠르게 응답한 개수를
보여주는 화려한 대쉬보드 만들어주세요 ^^
“
“
DevDjango Korea
평균? 최대값?
response_time 열만 모아서 계산하면 되는데..
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
Aggregation!!!
Aggregate를 사용해서 한 컬럼에 전체에 대해 계산할 수 있어요!
2. ORM뒤에 

숨겨진 블랙홀
run_qs.aggregate(Avg('response_time'), Max('response_time'))
DevDjango Korea
Level up!!!
run.response_time > ml_model.threshold인 

run의 총개수???
2. ORM뒤에 

숨겨진 블랙홀
저희 머신러닝 모델의 여러 버전마다 실행된 것들에서
8월 1일에서 8월 20일까지 실행된 것 들 중
error없이 실행된 active한 것들만 모아서
응답시간의 평균 값, 최대값
그리고 저희 모델에 설정한 스레숄드 값보다 빠르게 응답한 개수를
보여주는 화려한 대쉬보드 만들어주세요 ^^
“
“
DevDjango Korea
조건문은??
Case와 When을 쓰기!
2. ORM뒤에 

숨겨진 블랙홀
fast_runs=Count(
Case(
When(response_time__gt=F('ml_model_threshold'), then=1),
output_field=IntegerField(),
)
)
DevDjango Korea
Annotation!!!
특정 기준으로 값을 묶어 새로운 컬럼만들때는 annotation!
2. ORM뒤에 

숨겨진 블랙홀
run_qs.annotate(
fast_runs=Count(
Case(
When(response_time__gt=F('ml_model_threshold'), then=1),
output_field=IntegerField(),
)
)
).aggregate(Sum('fast_runs'))
DevDjango Korea
Aggregation!!!
그렇게 만든 컬럼을 다시 합쳐서 계산하면 끝!
2. ORM뒤에 

숨겨진 블랙홀
run_qs.annotate(
fast_runs=Count(
Case(
When(response_time__gt=F('ml_model_threshold'), then=1),
output_field=IntegerField(),
)
)
).aggregate(Sum('fast_runs'))
DevDjango Korea
2. ORM뒤에 

숨겨진 블랙홀
해냈다!!!
DevDjango Korea
SQL
ORM
SQL
이렇게 커넥션도 직접 쓰고..막 쿼리쓰면서 교집합 합집합하고 난리났는데..
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
ORM
run_qs = Run.objects.filter(
version__id__in=version_ids,
ml_model__id__in=version_ids,
is_active=True,
requested_at__range=(start_date, end_date)
)
run_qs.aggregate(Avg('response_time'), Max('response_time'))
run_qs.mannotate(
fast_runs=Count(Case(
When(response_time__gt=F(‘ml_model__threshold'), then=1),
output_field=IntegerField(),
))
).aggregate(Sum('fast_runs'))
ORM으로 할 수 있다니 대단해!!!

이제 ORM으로만 돌려봐야지!!!
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
실전 상황 2
Run.objects.all()

1초..

2초..

345초 ..

…
서버가 터졌습니다!!!!!
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
…
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
ORM 쉽다며...
믿었던 ORM으로 만든 지뢰밭..

어디서 터지고 왜 터지는지 이해할 수가 없어요..
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
ORM의 비밀..?!
세상에나, Run.objects.all()에서 터진게 아니었다?

여기서 터졌다고 해요
2. ORM뒤에 

숨겨진 블랙홀
runs = Run.objects.all()
for run in runs:
print(run.name)
WHY?!!!!
DevDjango Korea
왜???
사실 ORM은 매우 매우 게을러서(?)

ORM아 그렇게
놀기만 하다가
서버가 터지면
어쩌려고 그러니
2. ORM뒤에 

숨겨진 블랙홀
공부나해
ORM아	그렇게	
놀기만	하다가	
서버가	터지면		
어쩌려고	그러니
DevDjango Korea
왜???
진짜진짜 필요할 때까지는 DB에서 레코드를 가져오지 않는다고 해요.

…	
무념무상
2. ORM뒤에 

숨겨진 블랙홀
runs = Run.objects.all()
for run in runs:
print(run.name)
DevDjango Korea
왜???
가져오려면 이렇게 쿼리셋을 순회해야..

더	이상	미룰수	없음..	
2. ORM뒤에 

숨겨진 블랙홀
가져	
올게runs = Run.objects.all()
for run in runs:
print(run.name)
DevDjango Korea
심지어 저장해둠
나중에 또 쓸까봐 한 번 가져오면 캐시로 저장해둔다고해요

runs = Run.objects.all()
for run in runs:
print(run.name)
for run in runs:
print(run.name)
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
이미	
있음
그럼 실제로 쿼리를 어떻게 날리는걸까?
Django-debug-toolbar를 실행시켜봅니다.

오오 어디서 쿼리를 어떻게 날렸는지 다 알려줘요!!

2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
그런데..!
중복되는 쿼리가 굉장이 많다...!

코딩할 때 뭐든 중복은 안 좋은 거랬어..!
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
검색검색
쿼리 최적화하려면

데이터 set을 

“필요한 만큼만”

“웬만하면 한 번에!”

쏙쏙 가져와야한대요

인터넷에서 모은 꿀 팁들
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
먼저, 한 번에 가져오기!
ForeignKey는 select_related!

ManyToManyField는 prefatch_related!

2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
예를들면,
class Post(models.Model):
author = models.ForeignKey(Author)
tag = models.ManyToManyField(Tag)
2. ORM뒤에 

숨겨진 블랙홀
author을 ForeinKey

tag를 ManyToMany로가진

Post 모델!!
DevDjango Korea
ForeignKey는 select_related!
post = Post.objects.get(id=1)
author = post.author
2. ORM뒤에 

숨겨진 블랙홀
post가져올 때 한 번
DevDjango Korea
ForeignKey는 select_related!
post = Post.objects.get(id=1)
author = post.author
2. ORM뒤에 

숨겨진 블랙홀
author가져올 때 한 번
이렇게 가져오면 DB에 두번이나 갔다와야함

정색	 DevDjango Korea
한 번에 가져오기!
select_related로 한 번에 가져오기!
방긋	
post = Post.objects.select_related('author').get(id=1)
author = post.author
author값도 같이 가져와!
2. ORM뒤에 

숨겨진 블랙홀
굿굿
DevDjango Korea
ManyToManyField는 prefatch_related!

posts = Post.objects.all()
for post in posts:
for tag in post.tag_set.all():
print(tag)
2. ORM뒤에 

숨겨진 블랙홀
post 하나 돌 때마다
DevDjango Korea
ManyToManyField는 prefatch_related!

posts = Post.objects.all()
for post in posts:
for tag in post.tag_set.all():
print(tag)
2. ORM뒤에 

숨겨진 블랙홀
tag_set 가져오기..?
posts	백개면	백번..천개면	천번..
…
DevDjango Korea
posts = Post.objects.all().prfetch_related(‘tag_set')
for post in posts:
for tag in post.tag_set.all():
print(tag)
두 번으로 줄이기
감격
post다 가져온다음 tag_set도 다 가져와!
post.objects.all()
self.tag_set.all)()
2. ORM뒤에 

숨겨진 블랙홀
최고!
DevDjango Korea
ManyToManyField는 prefatch_related!
필요한 것만 가져오기!
아무 생각 없이 다가져오던 시절..

메모리따위 고려하지 않겠어!!

posts = Post.objects.all()
for post in posts:
print(post.name)
메모리
ㅠ ㅠ
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
필요한 것만 가져오기!
어떻게든 values, values_list로 줄여요…

ORM 무서워..
posts = Post.objects.values('name')
for post in posts:
print(post.name)
2. ORM뒤에 

숨겨진 블랙홀
메모리
^ ^
DevDjango Korea
있는지 없는지 확인하는데

posts 다 가져오면 낭비니까!
posts = Post.objects.all()
If posts:
print(posts)
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
필요한 것만 가져오기!
전부 vs 하나

가져오기

posts = Post.objects.all()
If posts.exists():
print(posts)
하나만 있는지 확인!
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
필요한 것만 가져오기!
꿀팁을 알았으니..
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
엄청나게 써먹을테야!!

지뢰밭 다 없애버리겠어!!
그 밖에도 무긍무진한 ORM의 블랙홀
틈틈히 정복하기로합니다!

오	알	ㅇ	ㅔ		ㅁ	어려워..
2. ORM뒤에 

숨겨진 블랙홀
DevDjango Korea
제3장.		
Transaction적용하다	celery에게	뒷통수	맞다!
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
ORM에게 호되게 당한 기분은?
역시 공부를 해야겠어요..!
Django책은 디자인도 간지나군요!!
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
7장을 읽던 중..
Transaction????
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
Transaction 감 잡았다! 요놈!
대충 감이 오는군
그니까 전부 없던 일로 쳐준다는거 아녀!!
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
0 아니면 1
쿼리 다 성공하던지, 다 없던 일로 하던지
쿼리 쿼리 쿼리 실패하면
원상복구
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
두리번 두리번
어디 써먹을 데 없나요? 

저 좋은거 득템했는데..
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
발견!!!
저 create() 함수에서 부모객체, 자식객체 둘 다 생성하군!
version

자식객체 생성!
ml_model

부모객체 생성!
def create(self, request, *args, **kwargs):
ml_model = Mlmodel.objects.create(
title=request.data.get('title', None)
)
tasks.build(ml_model.id)
version = Version.objects.create(
parent=ml_model
)
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
상상중...
자식 생성 도중 실패하면?

그럼 이미 만들어진 부모 객체는??
DevDjango Korea
version

자식객체 생성 실패!
ml_model

부모객체 생성!
def create(self, request, *args, **kwargs):
ml_model = Mlmodel.objects.create(
title=request.data.get('title', None)
)
tasks.build(ml_model.id)
version = Version.objects.create(
parent=ml_model
)
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
테스트 해보자!!
일만 아니면 왜이렇게 신이 날까 ~~
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
테스트 작성중...
실패하면 부모객체=Mlmodel 남아있는거야!!!

(실패하길 바라는 자)
def test_create_version_failed(self):
…
self.assertEqual(Version.objects.count(), 0)
self.assertEqual(Mlmodel.objects.count(), 0)
DevDjango Korea
def test_create_version_failed(self):
…
self.assertEqual(Version.objects.count(), 0)
self.assertEqual(Mlmodel.objects.count(), 0)
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
돌리고돌리고
통과!
DevDjango Korea
Version의 총 개수 == 0 !!
def test_create_version_failed(self):
…
self.assertEqual(Version.objects.count(), 0)
self.assertEqual(Mlmodel.objects.count(), 0)
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
과연 결과는?!
실패!
DevDjango Korea
Mlmodel의 총 개수 == 1 !!
DjangoCon3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
테스트 성공하도록 바꿔보자!
함수 전체에 @transaction을 적용!!
@transaction.atomic
def create(self, request, *args, **kwargs):
ml_model = Mlmodel.objects.create(
title=request.data.get('title', None)
)
tasks.build(ml_model.id)
version = Version.objects.create(
parent=ml_model
)
def test_create_version_failed(self):
…
self.assertEqual(Version.objects.count(), 0)
self.assertEqual(Mlmodel.objects.count(), 0)
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
테스트 통과!
통과!
통과!
PASSED!!!
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
세상 사람들!

제가 문제를 찾아서해결했어요!!!
똑똑한 척. 유능한 척. 문제를 제기합니다

으쓱으쓱
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
얼른 스테이징 환경에 적용해 봅시다!
+++ @transaction.atomic
CODE
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
create()! 얍!
Version.objects.create()

1초

2초

345초...

…
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
create()! 얍!
Version.objects.create()

1초

2초

345초...

…

Fail!!!!!!
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
… /// …
과거의 나야 나대지말란말이야!! 나도 같이 트랜젝션시켜줘!!
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
일 벌리고 수습하기
어디서	터졌나요..	
제발	알려줘요	
코딩신내림이라도..	
DevDjango Korea
@transaction.atomic
def create(self, request, *args, **kwargs):
ml_model = Mlmodel.objects.create(
title=request.data.get('title', None)
)
tasks.build(ml_model.id)
version = Version.objects.create(
parent=ml_model
)
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
가만…?!
그렇구나!! celery 테스크가 있었지!!
DevDjango Korea
@transaction.atomic
def create(self, request, *args, **kwargs):
ml_model = Mlmodel.objects.create(
title=request.data.get('title', None)
)
tasks.build(ml_model.id)
version = Version.objects.create(
parent=ml_model
)
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
flower를 보니까..
DevDjango Korea
DoesNotExist???!!! ml_model이 없다??
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션이 어떻게 작동하길래?
DevDjango Korea
(반성)	
이번엔 제대로 공부하고

수습해야겠어요..
@transaction.atomic
def create(self, request, *args, **kwargs):
ml_model = Mlmodel.objects.create(
title=request.data.get('title', None)
)
tasks.build(ml_model.id)
version = Version.objects.create(
parent=ml_model
)
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하기 전에는..
Django
ml_model =
Mlmodel.objects.create()
DB
성공!
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하기 전에는..
Django DB
ml_model row
commit!
DevDjango Korea
ml_model =
Mlmodel.objects.create()
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하기 전에는..
Django DB
version =
Version.objects.create()
성공!
DevDjango Korea
ml_model row
ml_model =
Mlmodel.objects.create()
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하기 전에는..
Django DB
Version row
commit!
DevDjango Korea
version =
Version.objects.create()
ml_model row
ml_model =
Mlmodel.objects.create()
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하면..
Django DB
DevDjango Korea
ml_model =
Mlmodel.objects.create()
성공!
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하면..
Django DB
DevDjango Korea
version =
Version.objects.create()
ml_model =
Mlmodel.objects.create()
성공!
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하면..
Django DB
commit!
DevDjango Korea
Version rowversion =
Version.objects.create()
ml_model row
ml_model =
Mlmodel.objects.create()
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
Celery task가 추가되면?
Django Celery
DB
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하기 전에는..
Django Celery
ml_model=
Mlmodel.objects.create()
성공!
DB
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하기 전에는..
Django Celery
DB
commit!
DevDjango Korea
ml_model=
Mlmodel.objects.create()
ml_model row
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하기 전에는..
Django Celery
DB
DevDjango Korea
ml_model=
Mlmodel.objects.create()
ml_model row
ml_model
get!
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하고는..
Django Celery
DB
DevDjango Korea
ml_model=
Mlmodel.objects.create()
성공!
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하고는..
Django Celery
DB
???
DevDjango Korea
ml_model =
Mlmodel.objects.create()
version =
Version.objects.create()
성공!
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
트랜잭션을 적용하고는..
Django Celery
DB
DoesNotExist!!!
commit!
늦었어!!!
DevDjango Korea
ml_model =
Mlmodel.objects.create()
version =
Version.objects.create()
ml_model row
version row
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
해결방안 찾기
지구에서 누군가는 .. 나와 똑같은 고민을 했지!
검색검색!
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
갓 구글...
영어로 답 나온거 실화냐..
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
역시 Django!!
Django에서 이런 때를 대비해!!

on_commit이라는 훅을 제공한대요
on_commit
transaction끝난 뒤

호출됩니다!!
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
Celery 기다려!
on_commit 훅을 사용해서 커밋이 다 끝난뒤

셀러리가 task를 하도록 설정!!
transaction.on_commit(lambda: celery_task.delay(‘version_id’))
DevDjango Korea
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
그리하여 celery가 commit을 기다린 후
Django Celery
DB
commit!
기다려!
DevDjango Korea
ml_model =
Mlmodel.objects.create()
version =
Version.objects.create()
ml_model row
version row
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
모델을 가져오도록 적용할 수 있었다고..
Django Celery
DB
ml_model row
ml_model!!!
version row
get!
DevDjango Korea
ml_model =
Mlmodel.objects.create()
version =
Version.objects.create()
3. 트랜젝션 적용하다
Celery에게 뒷통수 맞다
삽질했지만!
혼자 문제만들고 삽질하고...그래도 해결하고보니
완전	뿌듯해!!!!
DevDjango Korea
제4장.		
Django야	Django야	헌	집줄게	새	집다오
4. 헌집줄게 새집다오
옆자리 Frontend 개발자님의…
21살 쩌는 프론트개발자
특징: 엄~청나게 위대한 위장
DevDjango Korea
배고파요헤헤
계속배고파요
BIG 프로젝트…!!!
현재 서비스의 간지나는 

NEW 프론트 만들기!!!
두둥!!
힘들겠당ㅋㅋ
비 희
4. 헌집줄게 새집다오 DevDjango Korea
(반전)남 일인줄 알았나요?
멍....
4. 헌집줄게 새집다오 DevDjango Korea
DRF의 배신?
분명히	백엔드는	DRF로	돌아가서	api화	다되어있는데	
내가	할	일이	뭐가	있단	말이오..
4. 헌집줄게 새집다오 DevDjango Korea
궁금해???
Django가	하는	일이	엄청나게	많기	때문이지..!
4. 헌집줄게 새집다오 DevDjango Korea
그냥 Django
Url View Template
Django
Form
4. 헌집줄게 새집다오 DevDjango Korea
DRF + Template
Django와 DRF의 혼합물
Url
DRF
View
Template
Django
DRF
Serializer
Form
4. 헌집줄게 새집다오 DevDjango Korea
FormForm
DRF + Ccccccustom + Template
우리 플랫폼은 ... 어마어마한 커스트마이징
Url
DRF
View
Template
Django
DRF
Serializer
FormForm
4. 헌집줄게 새집다오 DevDjango Korea
FormForm
목표는??
흠..뭔가 이상한데??
Url
DRF
View
NEW
FRONT
Django
DRF
Serializer
FormForm
4. 헌집줄게 새집다오 DevDjango Korea
FormForm
엄청나게 뚱뚱한 Form의 존재..
저 Form은 어떻게…???
Url
DRF
View
NEW
FRONT
Django
DRF
Serializer
FormForm
4. 헌집줄게 새집다오 DevDjango Korea
FormForm
api에 집어넣어야..
Url
DRF
View
NEW
FRONT
Django
DRF
Serializer
FormForm
흡수!!!!!!
4. 헌집줄게 새집다오 DevDjango Korea
현실도피
저 많은 커스터마이징을 내가 다 api화 해야할리가 없어..
4. 헌집줄게 새집다오 DevDjango Korea
Form이 하던 Validation
Form이 하던 Validation은 Serializer에게 PASS
DRF
Serializer
DevDjango Korea4. 헌집줄게 새집다오
떠넘기기
Permission은 api따주고 프론트에게 넘기기!
DevDjango Korea4. 헌집줄게 새집다오
{  
              "permissions":[  
                 "Can execute this ml_model”,
                 "Can retrieve this ml_model”
              ]
           }
옛다! 이제 프론트에서 처리해
NEW
FRONT
(복수?)백엔드 번역해주기
문서화...해둘걸..(눈물)
은향님 이건 어떻게 처리해야해요?
은향님 이건 권한 설정 어때요?
은향님 이 폼 보여줘야해요?
은향님…
…
4. 헌집줄게 새집다오 DevDjango Korea
병행
대표님
스타트업은 lean해야하니꼬북!
필터 만들어주세요!
라이브러리 지원해주세요!
버전 비교하게 해주세요!
…
새로운 요구사항 + 뉴 프론트 지원 병행!
유저
4. 헌집줄게 새집다오 DevDjango Korea
이건 마치..
새	기능	만들기
4. 헌집줄게 새집다오 DevDjango Korea
이건 마치..
새	기능	만들기 새	기능	프론트	다시	만들기
4. 헌집줄게 새집다오 DevDjango Korea
이건 마치..
새	기능	만들기 새	기능	프론트	다시		만들기
또	새로운	기능	만들기
4. 헌집줄게 새집다오 DevDjango Korea
이건 마치..
새	기능	만들기 새	기능	프론트	다시		만들기
또	새로운	기능	만들기 또	새로운	기능	프론트	만들기
4. 헌집줄게 새집다오 DevDjango Korea
새	기능	만들기 새	기능	프론트	다시		만들기
또	새로운	기능	만들기 또	새로운	기능	프론트	만들기
무한한 꼬리잡기..
4. 헌집줄게 새집다오
에헤라디야~
잡히나봐라~
DevDjango Korea
시간이 흘러 흘러~~
그렇게 무려 3개월이 지나고.. 

드디어..드디어..! 뉴 프론트 합쳐서 올려봅시다..!
4. 헌집줄게 새집다오 DevDjango Korea
CSRF!!!!
CSRF
DevDjango Korea4. 헌집줄게 새집다오
뭐만하면 CSRF!!!
4. 헌집줄게 새집다오
고마해!!
DevDjango Korea
도대체 csrf??crfs??crsf??그게 뭔데!!!!!
너무	많이	쳐봐서	자동완성됨
4. 헌집줄게 새집다오 DevDjango Korea
1초 집중력
사이트	간	요청	우	ㅣ	조	ㄴ	ㅡㄴ...	
보안..보안은	1도	모른다능...
4. 헌집줄게 새집다오 DevDjango Korea
Stack Overflow 복붙(찡긋)
해결 됐으니..끝!!
4. 헌집줄게 새집다오 DevDjango Korea
머리채를 잡힌다..
flask로	만들던	서비스에서도..
4. 헌집줄게 새집다오 DevDjango Korea
CSRF..
아아아아알아내고	말것이야!!!!!
4. 헌집줄게 새집다오 DevDjango Korea
상상
유저가 브라우저에서 우리 서비스에 로그인하고 인터넷을 떠돌아다니다
User1 반가워요!
4. 헌집줄게 새집다오 DevDjango Korea
sessionid:
r37046e1944d532e3dc
2adf0d5c483fc
(주의!	session	id를	사용하여	인증할	때의	예를	든	것이에요!)
쿠키
4. 헌집줄게 새집다오 DevDjango Korea
어머나! 피싱사이트에 접속!
풰이크북.com
Save
상상
4. 헌집줄게 새집다오 DevDjango Korea
풰이크북.com
홀라당 덫에 걸려 CSRF공격 코드가 삽입된 버튼 click!!!
Save
나는. 유노윤호다.!
상상
4. 헌집줄게 새집다오 DevDjango Korea
풰이크북.com
Save
나는. 유노윤호다.!
<form action=“http://knowru.com/
user/reset_password/“
method=“POST”>
<input type=“hidden”
name=“password” value=“1234">
</form>
폼에는 우리 서비스에 비밀번호를 리셋하는 코드가..!
상상
4. 헌집줄게 새집다오 DevDjango Korea
브라우저에 저장된 쿠키와 함께 우리 서버로 요청을 보냈어요!
POST
http://knowru.com/user/
reset_password/
{password: ‘1234’}
sessionid:
r37046e1944d532e3dc2adf0d5c483fc
ㅋㅋㅋ
상상
4. 헌집줄게 새집다오 DevDjango Korea
발급해준 sessionid가 일치하니 비밀번호 리셋 성공!
User sessionid 인증성공!

200 OK!
?!
상상
그렇게	비밀번호는	해킹됐고	
해커가	우리	서비스를	탈탈털고...	
고객	서비스도	탈탈털고....	
메일이	쇄도하고..
4. 헌집줄게 새집다오
고객님 #$#$@#!@#!!!!@#!1
DevDjango Korea
상상…?!
파멸,,
csrf..	
django..	
주니어	개발자..	
안녕…;;
4. 헌집줄게 새집다오 DevDjango Korea
의욕 200%
당..당장 해결하겠습니다!

CSRF!!!
4. 헌집줄게 새집다오 DevDjango Korea
그래서 Django에서는 csrf를 어떻게 방어하나요?
CSRF문서에	친절하게	적혀있었다..!
4. 헌집줄게 새집다오 DevDjango Korea
Django와 CSRF
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
유저가 로그인을 요청했어요
GET:

로그인!!
Django와 CSRF
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
서버가 csrftoken을 쿠키에 저장하래요

GET:

로그인!!
csrftoken:
r37046e1944d532e3dc2adf0d5c483fc
Django와 CSRF
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
이제 모든 요청에 csrftoken값이 쿠키에 포함되어 전송되요.

유저가 Form 페이지를 요청했어요
GET:

Form페이지
‘csrf토큰’가지고있쿠키
Django와 CSRF
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
From에 hidden input을 넣어서 보냅니다!

바로 csrfmiddlewaretoken!
<form method="post">
<input type="hidden"
name="csrfmiddlewaretoken"
value="mTGKXN4BWSBd6wavFtK
SzBr...">
</form>
Django와 CSRF
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
<form method="post">
<input type="hidden"
name="csrfmiddlewaretoken"
value="mTGKXN4BWSBd6wavFtK
SzBr...">
</form>
from에 넣던 {% csrf_token %}이 저 input값이 되는거였어요!
{% csrf_token %}
Django와 CSRF
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
‘csrf토큰’가지고있쿠키
POST:

From 제출

(+csrfmiddlewaretoken)
이제 다시 쿠키와함께 Form을 제출합니다.
Django와 CSRF
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
서버가 두 값을 비교검증합니다!
csrftoken:
r37046e1944d532e3dc2adf0d5c
483fc
csrftmiddlewaretoken:
mTGKXN4BWSBd6wavFtKSzBr…
Django와 CSRF
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
검증이 성공하면 유저의 요청을 수행합니다!
201
Created!!
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
POST:
http://knowru.com/user/
reset_password/
우리서비스에 유저 비밀번호 reset 요청!
만약 CSRF공격이라면
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
csrfmiddlewaretoken이 없거나 틀린 값이겠네!!!
csrftoken:
r37046e1944d532e3dc2adf0d5c
483fc
???
만약 CSRF공격이라면
Forbidden!!
4. 헌집줄게 새집다오
이번엔	반가운	403!!
DevDjango Korea
그럼 Ajax는?
뭐지...이 엄청난 코드는....
DevDjango Korea
// using jQuery
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length +
1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
갖다쓰렴	^^
4. 헌집줄게 새집다오
그럼 Ajax는?
유저가 ajax로 전송할 Form 제출 버튼을 클릭하면
DevDjango Korea
Submit
Ajax로 데이터 전송!
4. 헌집줄게 새집다오
그럼 Ajax는?
csrftoken값을 해독해서 Request header에 저장!
DevDjango Korea
Request Header
{
X-CSRFToken: csrftoken
}
csrftoken:
r37046e1944d532e3dc2adf0d5c483fc
4. 헌집줄게 새집다오
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
POST:

From 제출

(+X-CSRFToken)
X-CSRFToken를 포함한 헤더와 폼제출!
그럼 Ajax는?
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
그럼 서버가 X-CSRFToken으로 온 값을 검증하고
그럼 Ajax는?
csrftoken:
r37046e1944d532e3dc2adf0d5c
483fc
X-CSRFToken
Django와 CSRF
User
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
검증이 성공하면 유저의 요청을 수행합니다!
201

Created!!
그렇다면 Angular는!!!
4. 헌집줄게 새집다오 DevDjango Korea
그렇다면 Angular는!!!
4. 헌집줄게 새집다오 DevDjango Korea
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
그렇다면 Angular는!!!
4. 헌집줄게 새집다오 DevDjango Korea
Angular와 같은 프론트엔드 프레임워크들은 

대부분 CSRF 대응을 지원하기 때문에!
그렇다면 Angular는!!!
4. 헌집줄게 새집다오 DevDjango Korea
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
이렇게 쿠키로오는 csrf토큰값이 무엇인지
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
Request보낼때 헤더에 포함할 값은 무엇인지만 

알려주면!
csrftoken:
r37046e1944d532
Django

Server
4. 헌집줄게 새집다오 DevDjango Korea
서버가 헤더에 포함된 토큰값을 검증할 수 있어요!
csrftoken:
r37046e1944d532e3dc2adf0d5c
483fc
X-CSRFToken
그렇다면 Angular는!!!
선 해결 후 이해
이렇게 우여곡절 끝에 뉴 프론트를 맞이하게됩니다!!!

간지폭팔!!!

4. 헌집줄게 새집다오 DevDjango Korea
비하인드 스토리
그 뒤로도 사실 또다른 몹들을 맞이하다

드디어 뉴 프론트를 서비스에 올렸어요

Lv10

npm

Lv20

China aws

Lv100000

NGINX

4. 헌집줄게 새집다오 DevDjango Korea
비하인드 스토리
NGINX설정이 안 먹어요 + 올리고보니 이런저런데서 또 터짐

4. 헌집줄게 새집다오 DevDjango Korea
비하인드 스토리
단호박
접읍시다꼬북!
4. 헌집줄게 새집다오 DevDjango Korea
비하인드 스토리
진-짜!!!

할 수 있어요!!!
4. 헌집줄게 새집다오 DevDjango Korea
흔들림
비하인드 스토리
24시간	안에	완성합시다!!!
4. 헌집줄게 새집다오 DevDjango Korea
비하인드 스토리
엄청난 집중력으로... 모든 에러를 해결!!!!

이런	모습	처음이야..!
4. 헌집줄게 새집다오 DevDjango Korea
비하인드 스토리
성공적으로 릴리즈하고 감격의 눈물을 흘렸다고..

4. 헌집줄게 새집다오 DevDjango Korea
제5장.		
삽질기는	계속된다-!
5. 삽질기는 계속된다!
그저께는
네트워크 공부해야겠다..!
AWS 설정하다가..https적용시키다..
Vpn…

Security Groups…

Load Balencers..

SSL..TLS..

DevDjango Korea
어제는
아냐..컴퓨터 기초부터..공부해야겠어..!
서버설정하다..
5. 삽질기는 계속된다! DevDjango Korea
오늘은
Python이나 제대로해야지..

컴퓨터부셨다	다시	조립해볼까..(화난거아님)
…
5. 삽질기는 계속된다! DevDjango Korea
그래도 사소한거에
유닛테스트..사방에서 터졌군
5. 삽질기는 계속된다! DevDjango Korea
햄볶!!
나 혼자 사방의 유닛테스트를 해결하디니..

(감격)
5. 삽질기는 계속된다! DevDjango Korea
어서와
Django는 처음이지?
낮은 진입장벽 덕분에
Djang언덕길을	발견했다!
5. 삽질기는 계속된다! DevDjango Korea
엄청	높은	산이었다!
비록 배신당하긴 했지만 겁나 높음
ㅋㅋㅋ
5. 삽질기는 계속된다! DevDjango Korea
왜 해야 하는지 몰랐던 공부를
프포자의	최강간지	모니터받침대!!!
5. 삽질기는 계속된다! DevDjango Korea
직접 찾아(즐겁게?)하게되고
내가	전공	책을	필요해서	직접	사읽고있다니..	
(이북 최고)
5. 삽질기는 계속된다! DevDjango Korea
고통받다..
외않되...
5. 삽질기는 계속된다! DevDjango Korea
느끼는 희열에 중독되고 있어요!!(?)
됐다!!!!!됐어!!!!(근데 왜되지?)
5. 삽질기는 계속된다! DevDjango Korea
삽질기는 계속!!
오늘도

내일도

모레도..

함께해요! ^^
5. 삽질기는 계속된다! DevDjango Korea
DjangoCon섹션네임
감사합니다! :)
DevDjango Korea
DjangoCon섹션네임
도움주신 분들!
파이님!

너굴님!

프로그라피 운명들 ㅇㅇㅇㅇㅇㅇㅇ! 

프로그라피 Django팀, 재규님, 성환님!

노루팀!

Javlon!

선우!

코알못 고향친구들!
날카로우면서	따뜻하고도	섬세한	리뷰	정말정말	감사해요.	최고.
DevDjango Korea

More Related Content

What's hot

Celery의 빛과 그림자
Celery의 빛과 그림자Celery의 빛과 그림자
Celery의 빛과 그림자Minyoung Jeong
 
Django admin site 커스텀하여 적극적으로 활용하기
Django admin site 커스텀하여 적극적으로 활용하기Django admin site 커스텀하여 적극적으로 활용하기
Django admin site 커스텀하여 적극적으로 활용하기영우 박
 
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵Javajigi Jaesung
 
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)Suhyun Park
 
[Td 2015]개발하기 바쁜데 푸시서버와 메시지큐는 있는거 쓸래요(김영재)
[Td 2015]개발하기 바쁜데 푸시서버와 메시지큐는 있는거 쓸래요(김영재)[Td 2015]개발하기 바쁜데 푸시서버와 메시지큐는 있는거 쓸래요(김영재)
[Td 2015]개발하기 바쁜데 푸시서버와 메시지큐는 있는거 쓸래요(김영재)Sang Don Kim
 
Doxygen 사용법
Doxygen 사용법Doxygen 사용법
Doxygen 사용법YoungSu Son
 
Django congress jp 2019 make query great again! (slide share)
Django congress jp 2019 make query great again! (slide share)Django congress jp 2019 make query great again! (slide share)
Django congress jp 2019 make query great again! (slide share)dattun
 
스타트업에서 기술책임자로 살아가기
스타트업에서 기술책임자로 살아가기스타트업에서 기술책임자로 살아가기
스타트업에서 기술책임자로 살아가기Hyun-woo Park
 
개발을잘하고싶어요-네이버랩스 송기선님
개발을잘하고싶어요-네이버랩스 송기선님개발을잘하고싶어요-네이버랩스 송기선님
개발을잘하고싶어요-네이버랩스 송기선님NAVER D2
 
NoSQL 위에서 MMORPG 개발하기
NoSQL 위에서 MMORPG 개발하기NoSQL 위에서 MMORPG 개발하기
NoSQL 위에서 MMORPG 개발하기Hoyoung Choi
 
190406 신입 클라이언트 프로그래머 1개월차까지 이야기
190406 신입 클라이언트 프로그래머 1개월차까지 이야기190406 신입 클라이언트 프로그래머 1개월차까지 이야기
190406 신입 클라이언트 프로그래머 1개월차까지 이야기KWANGIL KIM
 
How To Become Better Engineer
How To Become Better EngineerHow To Become Better Engineer
How To Become Better EngineerDaeMyung Kang
 
[MLOps KR 행사] MLOps 춘추 전국 시대 정리(210605)
[MLOps KR 행사] MLOps 춘추 전국 시대 정리(210605)[MLOps KR 행사] MLOps 춘추 전국 시대 정리(210605)
[MLOps KR 행사] MLOps 춘추 전국 시대 정리(210605)Seongyun Byeon
 
Django, 저는 이렇게 씁니다.
Django, 저는 이렇게 씁니다.Django, 저는 이렇게 씁니다.
Django, 저는 이렇게 씁니다.Kyoung Up Jung
 
신입 개발자 생활백서 [개정판]
신입 개발자 생활백서 [개정판]신입 개발자 생활백서 [개정판]
신입 개발자 생활백서 [개정판]Yurim Jin
 
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅DongMin Choi
 
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들Chris Ohk
 
새해 일어난 일
새해 일어난 일새해 일어난 일
새해 일어난 일Eunhyang Kim
 
Django - Python MVC Framework
Django - Python MVC FrameworkDjango - Python MVC Framework
Django - Python MVC FrameworkBala Kumar
 

What's hot (20)

Celery의 빛과 그림자
Celery의 빛과 그림자Celery의 빛과 그림자
Celery의 빛과 그림자
 
Django admin site 커스텀하여 적극적으로 활용하기
Django admin site 커스텀하여 적극적으로 활용하기Django admin site 커스텀하여 적극적으로 활용하기
Django admin site 커스텀하여 적극적으로 활용하기
 
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
소프트웨어 학습 및 자바 웹 개발자 학습 로드맵
 
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
 
[Td 2015]개발하기 바쁜데 푸시서버와 메시지큐는 있는거 쓸래요(김영재)
[Td 2015]개발하기 바쁜데 푸시서버와 메시지큐는 있는거 쓸래요(김영재)[Td 2015]개발하기 바쁜데 푸시서버와 메시지큐는 있는거 쓸래요(김영재)
[Td 2015]개발하기 바쁜데 푸시서버와 메시지큐는 있는거 쓸래요(김영재)
 
Doxygen 사용법
Doxygen 사용법Doxygen 사용법
Doxygen 사용법
 
Django congress jp 2019 make query great again! (slide share)
Django congress jp 2019 make query great again! (slide share)Django congress jp 2019 make query great again! (slide share)
Django congress jp 2019 make query great again! (slide share)
 
스타트업에서 기술책임자로 살아가기
스타트업에서 기술책임자로 살아가기스타트업에서 기술책임자로 살아가기
스타트업에서 기술책임자로 살아가기
 
개발을잘하고싶어요-네이버랩스 송기선님
개발을잘하고싶어요-네이버랩스 송기선님개발을잘하고싶어요-네이버랩스 송기선님
개발을잘하고싶어요-네이버랩스 송기선님
 
NoSQL 위에서 MMORPG 개발하기
NoSQL 위에서 MMORPG 개발하기NoSQL 위에서 MMORPG 개발하기
NoSQL 위에서 MMORPG 개발하기
 
190406 신입 클라이언트 프로그래머 1개월차까지 이야기
190406 신입 클라이언트 프로그래머 1개월차까지 이야기190406 신입 클라이언트 프로그래머 1개월차까지 이야기
190406 신입 클라이언트 프로그래머 1개월차까지 이야기
 
How To Become Better Engineer
How To Become Better EngineerHow To Become Better Engineer
How To Become Better Engineer
 
[MLOps KR 행사] MLOps 춘추 전국 시대 정리(210605)
[MLOps KR 행사] MLOps 춘추 전국 시대 정리(210605)[MLOps KR 행사] MLOps 춘추 전국 시대 정리(210605)
[MLOps KR 행사] MLOps 춘추 전국 시대 정리(210605)
 
Django, 저는 이렇게 씁니다.
Django, 저는 이렇게 씁니다.Django, 저는 이렇게 씁니다.
Django, 저는 이렇게 씁니다.
 
MongodB Internals
MongodB InternalsMongodB Internals
MongodB Internals
 
신입 개발자 생활백서 [개정판]
신입 개발자 생활백서 [개정판]신입 개발자 생활백서 [개정판]
신입 개발자 생활백서 [개정판]
 
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
 
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
 
새해 일어난 일
새해 일어난 일새해 일어난 일
새해 일어난 일
 
Django - Python MVC Framework
Django - Python MVC FrameworkDjango - Python MVC Framework
Django - Python MVC Framework
 

Similar to Django의 배신(주니어 개발자의 Django 삽질기)

Codegate 2014 - Bug Hunting Challenge [Track0]
Codegate 2014 - Bug Hunting Challenge [Track0]Codegate 2014 - Bug Hunting Challenge [Track0]
Codegate 2014 - Bug Hunting Challenge [Track0]sweetchip
 
2015 나는 프로그래머다 컨퍼런스 (11) 염산악 - 가독성에 대하여
2015 나는 프로그래머다 컨퍼런스 (11) 염산악 - 가독성에 대하여2015 나는 프로그래머다 컨퍼런스 (11) 염산악 - 가독성에 대하여
2015 나는 프로그래머다 컨퍼런스 (11) 염산악 - 가독성에 대하여iamprogrammerofficial
 
NDC2017 언리얼엔진4 디버깅 101 - 게임 기획자, 프로그래머가 버그와 만났을 때 사용할 수 있는 지침들
NDC2017 언리얼엔진4 디버깅 101 - 게임 기획자, 프로그래머가 버그와 만났을 때 사용할 수 있는 지침들NDC2017 언리얼엔진4 디버깅 101 - 게임 기획자, 프로그래머가 버그와 만났을 때 사용할 수 있는 지침들
NDC2017 언리얼엔진4 디버깅 101 - 게임 기획자, 프로그래머가 버그와 만났을 때 사용할 수 있는 지침들영욱 오
 
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)Dong Chan Shin
 
[NDC08] 최적화와 프로파일링 - 송창규
[NDC08] 최적화와 프로파일링 - 송창규[NDC08] 최적화와 프로파일링 - 송창규
[NDC08] 최적화와 프로파일링 - 송창규ChangKyu Song
 
OpenJigWare(V02.00.04)
OpenJigWare(V02.00.04)OpenJigWare(V02.00.04)
OpenJigWare(V02.00.04)Jinwook On
 
MongoDB in use(김인범, mongodb korea)
MongoDB in use(김인범, mongodb korea)MongoDB in use(김인범, mongodb korea)
MongoDB in use(김인범, mongodb korea)InBum Kim
 
안드로이드 빌드: 설탕없는 세계
안드로이드 빌드: 설탕없는 세계안드로이드 빌드: 설탕없는 세계
안드로이드 빌드: 설탕없는 세계Leonardo YongUk Kim
 
Let'Swift 2023 Swift Macro, 어디다 쓰죠?
Let'Swift 2023 Swift Macro, 어디다 쓰죠?Let'Swift 2023 Swift Macro, 어디다 쓰죠?
Let'Swift 2023 Swift Macro, 어디다 쓰죠?williciousk
 
04 생활 속 문제 해결을 위한 엔트리 프로그래밍
04 생활 속 문제 해결을 위한 엔트리 프로그래밍04 생활 속 문제 해결을 위한 엔트리 프로그래밍
04 생활 속 문제 해결을 위한 엔트리 프로그래밍entrylabs
 
김성훈 - 뛰어난 디버거가 되는 방법
김성훈 - 뛰어난 디버거가 되는 방법김성훈 - 뛰어난 디버거가 되는 방법
김성훈 - 뛰어난 디버거가 되는 방법성훈 김
 
Dodge the dodge_junsoolee
Dodge the dodge_junsooleeDodge the dodge_junsoolee
Dodge the dodge_junsooleeJunsoo Lee
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018Kenneth Ceyer
 
비동기와 이벤트큐 수업자료
비동기와 이벤트큐 수업자료비동기와 이벤트큐 수업자료
비동기와 이벤트큐 수업자료지수 윤
 
[16]Obfuscation 101 : 난독화, 프로가드, R8, 트랜스포머 API
[16]Obfuscation 101 : 난독화, 프로가드, R8, 트랜스포머 API[16]Obfuscation 101 : 난독화, 프로가드, R8, 트랜스포머 API
[16]Obfuscation 101 : 난독화, 프로가드, R8, 트랜스포머 APINAVER Engineering
 

Similar to Django의 배신(주니어 개발자의 Django 삽질기) (20)

Codegate 2014 - Bug Hunting Challenge [Track0]
Codegate 2014 - Bug Hunting Challenge [Track0]Codegate 2014 - Bug Hunting Challenge [Track0]
Codegate 2014 - Bug Hunting Challenge [Track0]
 
2015 나는 프로그래머다 컨퍼런스 (11) 염산악 - 가독성에 대하여
2015 나는 프로그래머다 컨퍼런스 (11) 염산악 - 가독성에 대하여2015 나는 프로그래머다 컨퍼런스 (11) 염산악 - 가독성에 대하여
2015 나는 프로그래머다 컨퍼런스 (11) 염산악 - 가독성에 대하여
 
NDC2017 언리얼엔진4 디버깅 101 - 게임 기획자, 프로그래머가 버그와 만났을 때 사용할 수 있는 지침들
NDC2017 언리얼엔진4 디버깅 101 - 게임 기획자, 프로그래머가 버그와 만났을 때 사용할 수 있는 지침들NDC2017 언리얼엔진4 디버깅 101 - 게임 기획자, 프로그래머가 버그와 만났을 때 사용할 수 있는 지침들
NDC2017 언리얼엔진4 디버깅 101 - 게임 기획자, 프로그래머가 버그와 만났을 때 사용할 수 있는 지침들
 
Tdd ver.2
Tdd ver.2Tdd ver.2
Tdd ver.2
 
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
C# / .NET Framework로 미래 밥그릇을 챙겨보자 (Basic)
 
[NDC08] 최적화와 프로파일링 - 송창규
[NDC08] 최적화와 프로파일링 - 송창규[NDC08] 최적화와 프로파일링 - 송창규
[NDC08] 최적화와 프로파일링 - 송창규
 
Node.js in Flitto
Node.js in FlittoNode.js in Flitto
Node.js in Flitto
 
OpenJigWare(V02.00.04)
OpenJigWare(V02.00.04)OpenJigWare(V02.00.04)
OpenJigWare(V02.00.04)
 
MongoDB in use(김인범, mongodb korea)
MongoDB in use(김인범, mongodb korea)MongoDB in use(김인범, mongodb korea)
MongoDB in use(김인범, mongodb korea)
 
안드로이드 빌드: 설탕없는 세계
안드로이드 빌드: 설탕없는 세계안드로이드 빌드: 설탕없는 세계
안드로이드 빌드: 설탕없는 세계
 
Python - Module
Python - ModulePython - Module
Python - Module
 
Let'Swift 2023 Swift Macro, 어디다 쓰죠?
Let'Swift 2023 Swift Macro, 어디다 쓰죠?Let'Swift 2023 Swift Macro, 어디다 쓰죠?
Let'Swift 2023 Swift Macro, 어디다 쓰죠?
 
Light Tutorial Django
Light Tutorial DjangoLight Tutorial Django
Light Tutorial Django
 
04 생활 속 문제 해결을 위한 엔트리 프로그래밍
04 생활 속 문제 해결을 위한 엔트리 프로그래밍04 생활 속 문제 해결을 위한 엔트리 프로그래밍
04 생활 속 문제 해결을 위한 엔트리 프로그래밍
 
김성훈 - 뛰어난 디버거가 되는 방법
김성훈 - 뛰어난 디버거가 되는 방법김성훈 - 뛰어난 디버거가 되는 방법
김성훈 - 뛰어난 디버거가 되는 방법
 
Dodge the dodge_junsoolee
Dodge the dodge_junsooleeDodge the dodge_junsoolee
Dodge the dodge_junsoolee
 
Node.js intro
Node.js introNode.js intro
Node.js intro
 
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
우아하게 준비하는 테스트와 리팩토링 - PyCon Korea 2018
 
비동기와 이벤트큐 수업자료
비동기와 이벤트큐 수업자료비동기와 이벤트큐 수업자료
비동기와 이벤트큐 수업자료
 
[16]Obfuscation 101 : 난독화, 프로가드, R8, 트랜스포머 API
[16]Obfuscation 101 : 난독화, 프로가드, R8, 트랜스포머 API[16]Obfuscation 101 : 난독화, 프로가드, R8, 트랜스포머 API
[16]Obfuscation 101 : 난독화, 프로가드, R8, 트랜스포머 API
 

Django의 배신(주니어 개발자의 Django 삽질기)