사실 지금은 코드를 보면 queryset에서 sorted된 값을 반환하고, 이경우에는 쿼리셋 자체가 저 변수로 할당되어버려 다음 request에서 쿼리가 돌지 않는다는 것을 쉽게 찾을 수 있다. 하지만 원래 한번 안보이면 잘 안보이는 법.. 심지어 이 경우에는 Exception이 나는 것도 아니기 때문에 더 찾기 어려웠다.. (ㅠㅠ)
삽질의 시작
여러가지 가정을 할 수 있는 상황이었다.
혹시 브라우저가 리스트를 캐싱하고 있던건 아닐까? (브라우저 캐시)
장고가 View의 Response를 캐싱하고 있는걸까? (장고 캐시)
혹시 DB에 save()가 안된(아예 DB가 업데이트가 되지 않은) 것은 아닐까?
장고 queryset에 캐싱이 되어있었을까?
AJAX call이 비정상적으로 이루어진 것은 아닐까?
아니면, 아예 내 View 로직이 잘못된 것은 아닐까? (CBV인데?)
select_related나 prefetch_related에서 캐싱이 발생하는걸까?
…
이런저런 가정을 하고 하나씩 체크를 해보기로 했다.
아래부분에서는 django 로직과 관련된 삽질만 다뤘습니다. JS쪽은 문제가 없었거든요.
widgets:
첫번째 삽질: “브라우저가 캐싱을 하고 있는건 아닐까?”
만약 브라우저가 HTML파일을 캐싱하고 있다면
캐시 삭제후 강력 새로고침을 하거나,
다른 브라우저로 접근하면
정상적인 화면이 나와야 했다.
그러나… “#망했어요”
브라우저가 캐싱하고 있는게 아니었고, 다른 브라우저에서도 기존(업데이트 전)값을 가져왔다.
widgets:
두번째 삽질: “장고가 template 렌더링 된것을 캐싱하는게 아닐까?”
사실 장고에서 response는 따로 캐싱을 명시적으로 하지 않으면 쿼리가 새로 발생해야 하는 경우에는 캐싱을 하지 않는다.
하지만 일단 template을 재 렌더링 하지 않는게 아닐까… 하는 생각에 아래와 같은 부분을 추가해 보았다.
1 2 3
{% raw %}{% for object in object_list %} {{ object }} 이건 object다 {% endfor %}{% endraw %}
역시 .. “응 아니야~ 장고 일 잘하고 있음”
템플릿은 렌더링이 충분히 잘 되고 있었다.
뭐가 문제일까?
widgets:
세번째 삽질: “.save() 메소드의 사용을 잘못한게 아닐까?”
아예 다음번에는 DB에 저장이 되지 않고 있는게 아닌가.. 하는 생각에 save()와 update()의 사용법을 찾고, force_insert=True와 같은 옵션을 넣어보기도 했다.
1 2 3 4 5 6 7 8 9
# view.py 파일에서... # ... for m_pay in mentor_payment_list: if str(m_pay.pk) in cleaned_keys: m_pay.status = 1 else: m_pay.status = 0 m_pay.save(update_fields=['status']) # ...
.save()는 모델 인스턴스에 적용하는 케이스이고, .update()는 쿼리셋에 적용하는 방법이다. save()의 경우 모델 인스턴스를 가져오기 위해 SELECT 쿼리를 한번 날리고 값을 변경 후 UPDATE를 해주는 방법이라면, update()는 쿼리 자체를 SELECT쿼리로 날리는 방식이다. 따라서 만약의 경우 .update()를 실행 중 다른 요청에서 값이 변경되었다면 그 Transaction이 손실될 수 있고, 모델 인스턴스의 값 자체를 이용해 업데이트하는 방법은 사용하기 어렵다. (물론 사용은 가능하지만 SELECT쿼리같이 .get()으로 한번 가져와야 하기때문에 큰 의미는 없습니다. 여전히 중간에 값이 변경되었을 경우에 기존 값(get)에 대한 불가능하고요.)
m_pay.save(update_fields=['status'])에서는 save()에 update_fields 리스트를 넣어주었다. 일반적인 save()함수가 인스턴스 전체를 변경하는 UPDATE문을 사용하지만 update_fields가 있는 경우에는 force_insert가 자동으로 True가 되며 동시에 해당되는 Column만 update가 일어난다.
사실 DJDT(Django Debug Toolbar)를 사용하며 쿼리의 개수를 확인해보는데 첫 요청시에는 6개의 쿼리가 가는데 비해 두번째 요청부터는 3개의 쿼리만이 실행되고, 그마저도 데이터를 가져오는 쿼리는 없고 세션/로그인등의 비교만 쿼리를 실행하고 있다는 것을 발견해 쿼리셋쪽의 문제라는 것을 알 수 있었다.
여담
문제의 코드 부분(아래)에서 select_related와 prefetch_related를 제거하면 쿼리수는 몇십개로 증가하지만 데이터 자체는 정상적으로 가져왔다. 이건 또 왜그랬을까?
1 2 3 4 5 6 7 8 9
# 문제의 코드.. classOrderMatchingList(ListView): classMeta: model = Order
You can’t use linux commands like git or ssh on your cmd, so we’re going to use great shell program which named cmder.
First, click this link:cmder.zip to download cmder. (It may take times.)
Second, unzip downloaded cmder.zip file. (It’ll take some times too.) And then you got this!:
Execute cmder.exe in this folder. If you execute cmder.exe as a first time you’ll be see Security Warning like this: just click RUN.
And one time more, if you execute cmder for the first time, there will be another warning like this: click first option, “Unblock and continue”.
It’ll take some times when you run cmder first time. This wouln’t appear next time, so please wait for a moment!
If you see this, you’re ready to use cmder NOW!
If you’re following DjangoGirls Tutorial, you probably made folder named djangogirls. Let’s get into it.
cd is command to ender the folder! Let’s get into djangogirls folder with cd djangogirls.
Let’s start deploy then.
Deploy Azure Virtual machine
You’ll see this screen if you logged in to Azure Portal.
Let’s make Virtual machine with clicking VirtualComputer(가상 컴퓨터) button.
Now let’s add Virtual machine with ‘+Add’ button.
If you click + Add button, you’ll see another options which provides many OS. But we’re going to use Ubuntu Server today.
If you clicked Ubuntu Server there’ll be server lists like this: we’ll use Ubuntu Server 16.04 LTS.
Then you’ll see Create button. Click it!
You’ll see configure window when you click Create button. Fillout blanks like picture lower.
Username should be django (surelly this is not critical but you may encounter issues.
You may set your password on your own, but it shoud be longer/equal than 12. Please remember not to reset it later.
Select locaiton on Korea Centeral or SouthEast Asia(which available one).
Now we have to choose server size. We’ll setup just one django server so we’ll choose DS1_V2, the left one.
Don’t worry, you won’t be charged :)
Next step you have to setup storage settings. Just select Use managed disks to ‘Yes’.
And then click Network Security Group(Firewall) settings. After click on it, you’ll see pre-configured setting SSH (TCP/22). We’re going to add HTTP (TCP/80)
Click + Inbound Rule add Button, and fillout blanks like this and click OK button.
Now default settings are finished! Just click OK button.
And one more time, click confirm button.
And lastly, click confirm button more! I know you’re tired with confirm button, but this is process of Azure :)
If you see your azure dashboard again like this, your server deployment is finished :)
Please wait until your server is successfully installed! (This will take upto 5mins.)
Your browser will redirected to your server info page when your server is successfully installed.
Get Azure Server Configurations
You can access to your server info with clicking server icon-which tells Running.
On this page you can see your server’s ‘Public IP Address’. ip is set of numbers which provides your computer access to internet. We can upload and deploy our django project through this ip.
You can see this example server’s ip, 13.67.60.234. Surelly we can access to our server with this numbers but we can’t remember easily with it.
So we’re going to use domain like djangogirls.com to that ip.
First of all, copy(CTRL+C) your virtual machine’s ip!
Get free domain and connect to Virtual Machine
You may know about popular domains like .com or .net. But they are paid one(10 dollars per year) so we’re going to use free domain.
This Dot.tk provides .tk domains as free! I’ll check djangogirls-seoul-tutorial-en.tk as example. You should think of your own domain name and click Check Availability!
Oh, it’s available! Just click ‘get it now’ button and add to cart.
You’ll see this page when you clicked ‘checkout’ button. Just click ‘Use DNS’ button and input ip address of your virtual machine(azure) and click ‘Continue’.
If you forgot ip address of your virtual machine, go to Azure portal and check your machine’s ip again!
You’ll see checkout page and you have to login. You can login with your social media account like Google or Facebook!
Sometimes there are some errors(404 or others..) then you can restart from “Get free domain and connect to Virtual Machine” on this guide.
If you successfully logined, you’ll see form to input your info, but you don’t have to fill it all. Just click Agress Terms and conditions and Conitnue button, your order will be finished!
Great! You’ve just connect your own domain to your server!
Install Fabric3
Now your server is connected with yourdomainname.tk domain. But if you try to access to that address, you can see nothing at all.
Because your server doesn’t have any django code and ofcourse, even django!
We’ll upload and deploy our django project with just one command line through Fabric3.
Let’s install fabric3 on our computer. You can install fabric3 with this command:
1
pip install fabric3
Remember: NOT fabric BUT fabric3! Don’t forget 3. fabric is python2 project.
Change REPO_URL, PROJECT_NAME, REMOTE_HOST. Other values are already setup for djangogirls tutorial we followed.
Every values must be in “”!
Upload and deploy code thorugh Fabric3
We can use fabric through fab command. Like this: fab new_server, fab deploy, fab create_superuser. This commands will execute commands on remote server(azure virtual machine which we made)
When you use fabric for new server, just type this command and execute: fab new_server. this will install python3, apache2, and mod_wsgi to run django.
1
fab new_server
When you edit django code and committed & pushed to github, then use fab deploy command. This will fetch latest code on github and migrate db.
1
fab deploy
When you want to create superuser, just execute fab create_superuser and there’ll be creating superuser prompt.
1
fab create_superuser
Whoa!
You’ve just upload and deploy REAL working web service on Azure! Congratulation!
Django 서비스를 실제 서버에 배포하면 보안을 위해 프로젝트 폴더의 settings.py파일 안의 DEBUG항목을 False로 두고 배포합니다. 이렇게 디버그모드를 끌 경우 장고에서 기본적인 보안을 제공해 줍니다. 그러나 만약 View나 Model에서 Exception이 발생했을 경우 클라이언트에 흰색의 500에러 화면만을 띄워줍니다.
이 경우 개발자에게도 장고의 에러 화면을 보여주지 않습니다. 따라서 Exception이 발생할 경우 개발자(혹은 운영자)에게 에러를 전송할 필요가 있습니다. wsgi 기반으로 서버를 구동할 경우 에러로그는 Apache2나 NginX등의 웹서버의 접근/에러로그가 있으며 Wsgi의 에러로그로 두가지가 있습니다.
장고서버의 경우에는 Wsgi의 에러로그에 로그를 쌓습니다. 그러나, Django 프로젝트에 LOGGERS 설정값을 추가해줘야 하며 에러 트래킹을 따로 설정해줘야 합니다.
장고 프로젝트의 settings.py파일 안 INSTALLED_APPS에 아래 줄을 추가해줍니다.
1 2 3 4
INSTALLED_APPS = [ # 기존 앱 가장 아래에 추가해주세요. 'raven.contrib.django.raven_compat', ]
이제 Sentry용 환경변수를 추가해 줍시다. 아래 DSN_URL은 Sentry에 로그인 하신 후 Sentry for Django의 코드 부분을 복사하면 알 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# settings.py 파일 import문 아래에 raven을 import해주세요. import os import raven
# import아래 환경변수를 설정해주세요. 이 URL은 위 Sentry for Django에서 바로 찾을 수 있습니다. DSN_URL = 'https://sampleurl1234141534samplesample:somemoreurl12341235dfaetr@sentry.io/123456'
# 기타 설정들(생략...)
# settings.py 파일 가장 아래에 RAVEN_CONFIG를 추가해주세요. RAVEN_CONFIG = { 'dsn': '{}'.format(DSN_URL), # DSN_URL을 위에 적어주셔야 동작합니다. 'release': raven.fetch_git_sha(BASE_DIR), # Django가 Git으로 관리되는 경우 자동으로 커밋 버전에 따른 트래킹을 해줍니다. }
Sentry wsgi.py에 설정하기
이제 장고 프로젝트 폴더 안의 wsgi.py 파일을 아래와 같이 수정해봅시다.
1 2 3 4 5 6 7 8 9 10
import os
from django.core.wsgi import get_wsgi_application from raven.contrib.django.raven_compat.middleware.wsgi import Sentry
# 이 부분은 여러분의 장고 프로젝트 이름을 쓰세요.. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "장고프로젝트이름.settings")