Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Django, 저는 이렇게 씁니다.

34,723 views

Published on

Django로 알파카코믹스 프로젝트를 진행하면서 겪은 몇가지 문제 해결에 대한 간략한 소개입니다.
파이썬 코리아 세미나에서 발표한 자료입니다.

Published in: Software

Django, 저는 이렇게 씁니다.

  1. 1. Django, 저는 이렇게 씁니다. 알파카코믹스를 개발하면서.
  2. 2. 안녕하세요. 풀 스택 개발자 파이입니다. 진짜로 서버 조립에서 디자인까지 해봄 스마트스터디에서 일하고 있습니다.
  3. 3. Django로 먹고 살아온 세월 5년 5년이면 많이 알겠네요?! 해본 것도 기억 못해요…
  4. 4. 발표 왜 하세요? 일 만하다 보니 제가 뭐하고 있나 싶었어요. 기억력이 안 좋아서 방금 짠 코드도 까먹습니다. 잊기 전에 뭐라도 남기고 싶었습니다. 아는 것도 별로 없지만 막상 적으려면 더 없어요. OTL 해본 거 탐험이 필요한 미지의 영역 아는 거 발표
  5. 5. Django 왜 쓰나요? 할 일은 많고 사람은 없을 때. 시간도 없을 때. 귀찮을 때.
  6. 6. 알파카코믹스를 개발하면서 만들면서 겪은 문제들을 어떻게 해결(땜빵)했는지 간략하게 이야기해보겠습니다.
  7. 7. 프로젝트를 시작할 때 신경 쓰는 게 신상에 이롭습니다.
  8. 8. 모델이 제일 중요합니다. 모든 것의 근원, 데이터의 흐름 가장 오랫동안 고민해도 부족하지 않습니다. 많은 연습을 필요로 합니다.
  9. 9. 모듈을 용도 별로 나누세요. 천 줄 짜리 코드를 나중에 다시 열면 내가 짠 거 알면서도 욕이 나옵니다. 모델에 기초해서 어떻게 하든 나누세요.
  10. 10. 예) 프로젝트 레이아웃 /alpaca /comic /profile /... /conf /production /settings.py /testing 앱 내부 배포 환경에 따른 세팅
  11. 11. Python 가상 환경은 선택이 아닌 필수 pyenv https://github.com/yyuu/pyenv virtualenv wrapper https://pypi.python.org/pypi/virtualenvwrapper
  12. 12. Front-end는 Bower로 관리 bower.json { "name": "alpacacomics", "dependencies": { "jquery": "1.9.1", ….. } } .bowerrc {"directory":"alpaca/static/components"} $ bower update
  13. 13. User에 cash 넣을래요.
  14. 14. Profile Model과 OneToOneField profile/models.py class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL) cash = models.IntegerField(defalut=0) user.profile.cash 로 접근 http://perhapsspy.wordpress.com/2013/02/18/a-simple-way-how-to-extend-user-model-in-django-1-5/
  15. 15. Profile 모델에 관련 함수 모으기 캐시 충전 캐시 환불 스토어 별 캐시 ex) user.profile.cash_charge(...)
  16. 16. 장점 다른 라이브러리와 충돌 걱정 없다. 관리도 쉽다. 구현이 제일 쉽다. 2가지 방법이 더 있으나 쉬운 게 최고…..는 아니고 상황에 맞게 찾아 쓰세요.
  17. 17. 소셜 로그인이 필요해요.
  18. 18. Django-allauth 이름처럼 모든 것을 해줌. 일반 가입, 소셜 로그인 및 관리, 이메일 인증, 비밀번호 찾기, 등. 단, 한글은 직접 .po 파일을 만들어야...(or template) 잘 쓰려면 adepter도 고치고...
  19. 19. template을 적당히 고쳐서 쓰면 그럴 듯합니다.
  20. 20. 스크롤을 내리면 이어지게 ajax 지옥...
  21. 21. HTML을 조각조각 따따따 template_name = ‘item_list.html’ if request.is_ajax(): template_name = ‘_item.html’ javascript는 최대한 단순하게. 하지만 아무래도 귀찮다. 맘에 들게 널 다시 조립할거야
  22. 22. CBV로 한번 만들고 계속 쓰자. 반복 작업을 싫어하시는 당신을 위한 CBV - Class Based View 만들어둔 Class를 조립해서 쓴다. https://docs.djangoproject.com/en/1.7/topics/class-based-views/
  23. 23. Mixin을 써보자 class ChangeTemplateMixin(object): # ajax 요청이 들어오면 template 변경 class MoreListMixin(ChangeTemplateMixin): # 무한 스크롤 구현 class CashUseLogView(MoreListMixin, ListView): # 위의 믹스인을 합쳐서 날로 먹기 class CashChargeLogView(MoreListMixin, ListView): # 계속해서 날로 먹기
  24. 24. 이렇게 됩니다.
  25. 25. RESTful API가 필요한데요.
  26. 26. Django REST framework 기능이 엄청 많습니다. CBV로 API를 만들 수 있습니다. 즉, 모델만 잘 짜두면 순식간에 만듭니다. 단순한 API는 1~2시간이면 뚝딱. 하지만 속도가 느리다는 게 함정. 자세한 설명은 문서 참고하세요. 최근에 3.0까지 나왔습니다. http://www.django-rest-framework.org/
  27. 27. 사이트가 느려요. DB와 Cache로 해결해봅시다.
  28. 28. DB 쿼리 최적화 두 가지만 기억하세요. 222쿼리가 2쿼리로 줄어드는 마법이 벌어집니다. select_related - Foreign-key 관계 prefetch_related - Many to Many 관계 여러 쿼리를 join으로 합쳐줍니다.
  29. 29. 예) DB 쿼리 최적화 Comic.objects.all().select_related(‘author’) .prefetch_related(‘tags’) Product.objects.get(id=1).select_related( ‘episode’, ‘episode__comic’)
  30. 30. CBV는 어떻게 쿼리 최적화 하나요. class CashUseLogView(MoreListMixin, UserFilterMixin, ListView): model = CashUseLog template_name = 'cash/use_log.html' ajax_template_name = 'cash/_use_log.html' def get_queryset(self): return super(CashUseLogView, self).get_queryset() .select_related('product', 'product__episode__comic', 'product__episode') class ComicDetail(MoreListMixin, ProductsMixin, SingleObjectMixin, ListView): def get(self, request, *args, **kwargs): queryset = Comic.objects.all() .select_related('author', 'category') .prefetch_related('tags') self.object = self.get_object(queryset=queryset) return super(ComicDetail, self).get(request, *args, **kwargs) 이렇게
  31. 31. Cache를 바릅니다. View, Template 등을 상황에 맞춰 적당히(!?!) Cache의 핵심 어느 타이밍에 갱신할 것인가?
  32. 32. 데이터가 변하면 갱신하자. class Comic(models.Model): … def save(....): cash_update()
  33. 33. 이것도 Class로 만들어 두고 조립. class Comic(CacheDeleteModel, models.Model): … def save(....): cash_update()
  34. 34. Django-compressor staic 파일들을 압축해준다. STATICFILES_FINDERS = ( ... "compressor.finders.CompressorFinder", ) COMPRESS_OFFLINE = True COMPRESS_CSS_FILTERS = {'compressor.filters.cssmin.CSSMinFilter',} COMPRESS_OFFLINE_CONTEXT = {'STATIC_URL': "/static/",} $ python manage.py compress https://github.com/django-compressor/django-compressor
  35. 35. Admin 페이지 어떻게 써요?
  36. 36. 예) admin.py def release_display(instance): if instance.release: return instance.release.strftime('%y.%m.%d %H:%M') return instance.release release_display.admin_order_field = 'release' release_display.short_description = u'출시일시' class ComicAdmin(admin.ModelAdmin): list_display = ['id', 'category', 'name', 'author', 'publisher', 'rating', 'view_count', 'purchase_count', 'active', 'end', release_display, 'recommended', 'weight', 'last_weight', 'login_required_episode', 'episode_count'] list_filter = ['active', 'category', 'rating', 'recommended', 'service_ext'] list_editable = ['recommended', 'weight', 'last_weight', 'login_required_episode'] raw_id_fields = ['author', 'publisher', 'tags'] readonly_fields = ['view_count', 'purchase_count', 'episode_count'] def get_queryset(self, request): return super(ComicAdmin, self).queryset(request) .select_related('category', 'author', 'publisher') admin.site.register(Comic, ComicAdmin) 쿼리 최적화
  37. 37. 예) Admin 화면 아래와 같이 대충 쓸 만해집니다.
  38. 38. 기타 다른 Admin 설정 list_display_links : 목록에서 누를 수 있는 링크가 되는 필드 list_per_page : 목록의 아이템 수 date_hierarchy : 지정한 날짜 필드 기준 필터 생성 ordering : 순서 search_fields : 검색 대상 필드
  39. 39. 배포는?
  40. 40. 제가 자주 씁니다. OS : Ubuntu Web Server : Nginx App Server : uWSGI Django Version : 1.7+ Database : Mysql or Postgresql 설정하기 쉽다는 공통점이 있습니다.
  41. 41. 간단한 스크립트. git pull cp nginx.conf /etc/nginx/site-enabled/app pip install -r requirements.txt bower update python manage.py collectstatic service nginx reload service uwsgi reload
  42. 42. 사실 Docker 쓰고 있어요. 방금 전 스크립트는 Dockerfile 흉내. Docker registry (회사 전용) Gadget (배포 도구)
  43. 43. 요약하겠습니다. 힘들어서 여기까지만.
  44. 44. 그러니까, ● 모델이 제일 중요합니다. ● User 모델 확장은 OneToOne ● 소셜 로그인은 Django-allauth ● 반복 작업은 CBV ● DB최적화는 select_related, prefetch_related ● Cache는 컨트롤이 중요 ● Admin는 django 핵심 기능입니다.
  45. 45. 질문 받습니다. 더 많은 것을 담아보려다 체력이 고갈 되어 질문으로 넘어갑니다.
  46. 46. 감사합니다. 끝.

×