Codong's Development Diary RSS 태그 관리 글쓰기 방명록
python/django (3)
2022-12-25 22:05:55

개요

도커를 이용해서 mysql db를 사용하는 django project를 만들고 싶었다.

도커만 설치하면 어디서든 쉽게 실행시킬 수 있다는 장점이 넘 달달하죠잉~🍯



본문

1. docker compose 세팅

대충 나는 아래와 같이 기본적인 것만 해뒀다.

# docker-compose.yml
services:
  db:
    image: mysql:5.7
    container_name: example
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: "test"
      MYSQL_USER: "root"
      MYSQL_ROOT_PASSWORD: "test1234"
    volumes:
      - ./mysql:/var/lib/mysql:rw
      - ./docker/mysql/conf.d:/etc/mysql/mysql.conf.d:ro # mysql setting 적용을 위함.

맨 아랫줄은 mysql setting 값들을 파일로 적용시키기 위함이다. 아래 사진 참고.

출처 : https://hub.docker.com/_/mysql


2. DB 생성 확인

~ ❯ docker exec -it drf-example /bin/bash
root@937526738ea0:/# mysql -u root -ptest1234
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.38-log MySQL Community Server (GPL)

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.07 sec)

mysql>

원했던 대로 test db가 잘 생성되어있는 것을 확인할 수 있다.


3. django config

DATABASES = {
    'default' : {
        "ENGINE": "django.db.backends.mysql",
        'NAME': 'test',
        'USER': 'root',
        'PASSWORD': 'test1234',
        'HOST': 'localhost',
        'PORT': '3306',
    }
}

4. django 서버 실행

~/drf_example ❯ python manage.py runserver
...
django.db.utils.OperationalError: (2002, "Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)")

뜬금없이 socket 파일을 못 찾는다 ㅇㅈㄹ 너무 화가 남.... 이거 때문에 조금 시간을 허비했다....

구글링 결과 알고 보니 django settings 파일에 db host 값을 localhost라 하면 django가 db 통신을 tcp로 하는 게 아닌 소켓으로 해버린단다...

ref. https://stackoverflow.com/questions/58029324/2002-cant-connect-to-local-mysql-server-through-socket-run-mysqld-mysqld-so

host 값을 '127.0.0.1'로 바꾸면 아주 가뿐하게 실행된다~~

2021-03-20 22:36:53

😆 개요


django로 웹 서비스를 만들어 보면서 비동기 방식을 안 써볼 수가 없다. 그!래!서! 비동기 통신 방식으로 많이 이용하고 있는 jquery의 ajax의 정말 기초적이 사용방법을 알아보려고 한다. 혹시라도 도움이 되는 분들이 있을까봐 포스팅하게 되었다.
(사실 내가 모르고 있어서 안 까먹으려고..)

시작하기 앞서, ajax가 뭘까?라는 생각이 먼저 든다.


Ajax(Asynchornous Javascript And XML)란?

AJAX란, JavaScript의 라이브러리중 하나이며 Asynchronous Javascript And Xml(비동기식 자바스크립트와 xml)의 약자이다. 브라우저가 가지고있는 XMLHttpRequest 객체를 이용해서 전체 페이지를 새로 고치지 않고도 페이지의 일부만을 위한 데이터를 로드하는 기법 이며 JavaScript를 사용한 비동기 통신, 클라이언트와 서버간에 XML 데이터를 주고받는 기술이다.

즉, 쉽게 말하자면 자바스크립트를 통해서 서버에 데이터를 요청하는 것이다.


😎 Vㅔ리 간단한 사용법.


너무 쉬우므로 묻고 코드로 간다.

1️⃣ html 부분

<!-- head 부분 -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<!-- body 부분 -->
<script type="text/javascript">
$('#submit').on('click', function(e) {
    data = $('#text').val();
    $.ajax({
        type:'POST',
        url:'127.0.0.1:8000/home',
        data:JSON.stringify(data),
        success:function(json){
            console.log("data pass success",json);
        },
        error : function(xhr,errmsg,err) {
        console.log(xhr.status + ": " + xhr.responseText); 
        }
   });
  });


</script>

ajax 부분을 원하는 이벤트 function(위 예제에선 submit click시)안에 넣어주면 된다. 중간중간 나오는 $는 jquery 문법이다.


➕ jquery란?

  • 웹사이트에 자바스크립트를 쉽게 활용할 수 있도록 도와주는 오픈소스 기반의 자바스크립트 라이브러리다.
  • 간단하게 웹페이지 상에서 $ 를 사용해서 Element를 쉽게 찾고 조작할 수 있다.
    • $('#foo') = id가 foo 인 Element
    • $('.foo') = class가 foo 인 Element

➕ data:JSON.stringify(data) 에서 JSON.stringify를 사용하는 이유

  • 요청을 받는 views.py에서 json 파싱을 수월하게 하기 위해 str형태로 만들어서 보냄.

2️⃣ 요청을 받는 views.py 부분

from django.http import JsonResponse

def home(request):
    # POST 요청일 때
    if request.method == 'POST':
        data = json.loads(request.body)
        # do something
        print(data)

        context = {
            'result': data,
        }
        return JsonResponse(context)

home function에서 받은 데이터를 json.loads로 dic로 만들어서 사용할 수 있다. 그렇게 받은 데이터를 요리조리 조리하고, 다시 결과값을 dict형태로 만들어서 JsonResponse를 이용해서 전달한다.


➕ flask 쓸 때처럼 그냥 return json.dumps(context)를 해서 보내면 아래와 같은 에러가 뜬다..

AttributeError: 'str' object has no attribute 'get'
[20/Mar/2021 11:36:08] "POST /home HTTP/1.1" 500 60851

🤗 마무리


아주 기초적인 부분인데 이런 것에 막혀서 시간을 뻈겼던, 쉬운 방법이 있었는데 어렵게 하던 내 자신이 부끄럽긴 하지만… 그래도 이런 기회를 통해 알게 됐다!! 안까먹기 위해서 포스팅을 많이많이 해두자..😢


reference

2021-03-20 21:54:25

😄 개요


간만에 장고로 다시 개인적인 toy project를 해보고 싶어서, 장고 프로젝트 생성하고 간단하게 POST 요청 비동기통신을 이용해보고 싶어서 jquery의 ajax를 사용했다. 역시, ERROR가 안뜰리 없다.


😱 문제점


우선 작성한 코드는 아주 간단했다.

$.ajax({
      type:'POST',
      url:'/search',
      data:JSON.stringify(geodata),
      success:function(json){
          console.log("to view data pass success",json);

      },
      error : function(xhr,errmsg,err) {
      console.log(xhr.status + ": " + xhr.responseText); 
      }
      });

search 로 POST 요청을 보냈는데.......?

Forbidden (CSRF cookie not set.): /search
[20/Mar/2021 10:47:16] "POST /search HTTP/1.1" 403 2864

결과는 처참했다....☠️☠️☠️☠️☠️

간단하게 요약하자면 django의 CSRF(Cross Site Request Forgery 사이트 간 요청 위조) 보안 정책으로 인해 일어난 에러이다.


👍 해결법


1️⃣ decorator를 사용하여 특정 view에 csrf 적용하지 않기

단순하게 csrf 정책을 사용하지 않는 것이다. 방법은 아주 간단하다. views.py에 원하는 view에 decorator를 달아주면 된다.

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def search(request):

    return HttpResponse('success')

이렇게 하면 해결되지만, 뭔가 보안상 뭔가 찜찜하다.. 그래서 다음 방법을 준비했다❗️


2️⃣ html 파일 header부분에 csrf token 생성하기

이 방법은 django 공식 문서(보러가기)에 있는 방법이다. ajax를 사용하는 html 파일의 header 부분에 아래 코드를 작성하면 된다.

<script>
  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 = cookies[i].trim();
              // 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);
          }
      }
  });
</script>

대강 보면 토큰을 만들고 ajax에 미리 설정해주는 것 같다. 필요한 사항은 당연히 jquery를 먼저 불러와야 한다.


➕ 2021/04/08 내용 추가

후에 위의 방법으로도 됐다가 안 됐다가 하다가 결국 또 안되길래 간단한 다른 방법을 찾았다.

<script>
  $.ajaxSetup({
    headers: { "X-CSRFToken": '{{csrf_token}}' }
  });
</script>

단순히 이 부분만 html 파일의 header 부분에 추가해주면된다... 이것 때문에 시간 또 날린거 너무 화나네🤬


😂 마무리


처음 배울 때에는 어떤 것인지도 모르고 단순히 에러만 없애려고 사용했었는데, 다시 보니 감회가 새롭고 오히려 더 기억에 남게 되었던 것 같다. 하지만 내 머리를 너무 믿지 말자. 오늘도 포스팅... 포스팅...🧑‍💻


reference

'python > django' 카테고리의 다른 글

[django] mysql + docker-compose  (1) 2022.12.25
[django] ajax를 이용해서 데이터 주고받기  (0) 2021.03.20