웹개발 플러스 - 02주 개발일지

우진님·2021년 7월 25일
0

본 내용은 스파르타 코딩클럽 웹개발 플러스 2주차 강의의 정리본 입니다 :D
본 수업을 듣고싶으시면 아래 링크를 클릭하여 친구추천 이벤트로 5만원을 할인 받으실 수 있습니다 !!

sparta coding club 친구 링크 : https://spartacodingclub.kr/?f_name=%ED%99%8D%EC%9A%B0%EC%A7%84&f_uid=6099457322dccf3b2ac8b84c
(위 링크에서 강의 결제시 5만원 할인이 적용됩니다!)

2주차 프로젝트는 owlbot api를 이용한 나만의 단어장 만들기가 프로젝트였다.

우리가 웹개발 할때 알아야하는 지식!

01. 플라스크로 멀티페이지 사이트 만들기 - 기초

  • 1) 페이지 간 이동하기

    메인 페이지에서 링크를 클릭하면 상세 페이지로 가고, 상세 페이지에서 다시 메인으로 갈 수 있게 하려면 어떻게 해야할까요?

    • 우선 파이참으로 이번주의 프로젝트를 준비해야겠죠!

      • File > New Project...에 가서 project02 폴더 열기

      • Project Interpreter에서 가상환경에 필요한 패키지 설치하기(flask, requests, pymongo)

      • project02 폴더 안에 templates, static 폴더 만들기

      • app.py, index.html, detail.html 파일 만들기

        • [코드스니펫] - app.py 시작코드

          from flask import Flask, render_template
          
          app = Flask(__name__)
          
          @app.route('/')
          def main():
              return render_template("index.html")
          
          @app.route('/detail')
          def detail():
              return render_template("detail.html")
          
          if __name__ == '__main__':
              app.run('0.0.0.0', port=5000, debug=True)
    • 페이지 연결하기

      • 상세 페이지로 가는 하이퍼링크는 이렇게 만듭니다.

        <a href="/detail">상세 페이지로 가기</a>
      • 메인 페이지로 돌아가는 버튼은 이렇게 만들 수 있겠죠!

        // script 태그 안에 정의하기
        function to_main() {
            window.location.href = "/"
        }
        <!-- 버튼에 함수 연결하기 -->
        <button onclick="to_main()">메인으로 돌아가기</button>
      • 짧은 코드는 onclick에 바로 넣을 수 있습니다.

        <button onclick='window.location.href = "/"'>메인으로 돌아가기</button>
  • 2) Jinja2 템플릿 언어 이용하기

    • 서버에서 name이라는 이름으로 값을 보내줍니다.

      @app.route('/')
      def main():
          myname = "sparta"
          return render_template("index.html", name=myname)
    • html 파일에서 이 값이 들어갈 자리를 표시해줍니다.

      ```html
      <h3>Hello, {{ name }}!</h3>
      ```

      파이참 Settings(맥은 Preferences) > Languages & Frameworks > Template Languages에서 템플릿 언어를 Jinja2로 설정해주면 자동완성과 하이라이팅 기능을 사용할 수 있어요!

이부분 응용하기!

02. 플라스크로 멀티페이지 사이트 만들기 - 응용

  • 3) Jinja2 템플릿 언어 이용하기 응용편

    • Jinja를 본격적으로 쓰기에 앞서, 원래 ajax 요청을 보내 html을 완성할 때는 어떻게 했었는지 살펴봅시다. 서울시 Open API에서 정보를 받아와 현재 미세먼지 수치가 50 이상인 구만 페이지에 나타내볼까요?

      • [코드스니펫] - ajax 요청 준비

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
        <script>
            $(document).ready(function () {
                get_list()
            })
        
            function get_list() {
                $.ajax({
                    type: "GET",
                    url: "http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99",
                    data: {},
                    success: function (response) {
                        let rows = response["RealtimeCityAir"]["row"];
                        console.log(rows)
                    }
                })
            }
        </script>
      • 미세먼지 정보가 들어갈 ul 태그 만들기

        <ul id="gu-list">
        </ul>
      • 각 구에 대해서 구 이름과 미세먼지 수치를 변수에 저장하기

        for (let i=0;i<rows.length;i++) {
            let gu_name = rows[i]["MSRSTE_NM"]
            let gu_mise = rows[i]["IDEX_MVL"]
            console.log(gu_name, gu_mise)
        }
      • 미세먼지 수치가 50 이상일 때만 태그 추가하기

        if (gu_mise >= 50) {
            let html_temp = `<li>${gu_name}: ${gu_mise}</li>`
            $("#gu-list").append(html_temp)
        }
    • 이번에는 같은 일을 jinja2로 해보겠습니다.

      • [코드스니펫] - requests 요청 보내기

        r = requests.get('http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99')
        response = r.json()
        rows = response['RealtimeCityAir']['row']
      • 렌더링할 html에 미세먼지 정보 보내기

        return render_template("index.html", name=name, rows=rows)
      • 첫번째 구의 정보를 태그로 만들기

        <li>{{ rows[0].MSRSTE_NM }}: {{ rows[0].IDEX_MVL }}</li>
      • 변수에 저장하기

        {% set gu_name = rows[0].MSRSTE_NM %}
        {% set gu_mise = rows[0].IDEX_MVL %}
        <li>{{ gu_name }}: {{ gu_mise }}</li>
      • 모든 구에 대해서 태그 만들기

        {% for row in rows %}
            {% set gu_name = row.MSRSTE_NM %}
            {% set gu_mise = row.IDEX_MVL %}
            <li>{{ gu_name }}: {{ gu_mise }}</li>
        {% endfor %}
      • 미세먼지 수치가 50 이상일 때만 태그 만들기

        {% if gu_mise >= 50 %}
            <li>{{ gu_name }}: {{ gu_mise }}</li>
        {% endif %}
    • 그 외에도, head 태그 안의 내용(title 태그 등)을 바꿀 때도 쓸 수 있고, 다른 html 문서를 통째로 가져와 템플릿으로 사용할 수도 있습니다.

  • 4) URL의 일부를 변수로 받기

    • 브라우저에 HTML을 띄우는 것은 GET 요청이기 때문에, 주소 뒤에 ?를 붙여 파라미터를 넘겨줄 수 있습니다.

      • 브라우저에 해당 API로 요청 보내기

        http://localhost:5000/detail?word_give=hello
      • 서버에서 파라미터 값을 받아 HTML으로 넘겨주기

        @app.route('/detail')
        def detail():
            word_receive = request.args.get("word_give")
            return render_template("detail.html", word=word_receive)
      • HTML에서 word라는 변수에 저장된 값 나타내기

        받은 단어는 {{ word }}
    • 플라스크 프레임워크에서는 URL의 일부를 변수로 받는 방법도 사용할 수 있습니다.

      @app.route('/detail/<keyword>')
      def detail(keyword):
          return render_template("detail.html", word=keyword)

그럼 단어장 만들러 start!

01.[설계하기]프로젝트 2: 나만의 단어장

  • 9) 문제 분석 - 완성작부터 보기: 나만의 단어장

    • [코드스니펫] - 나만의 단어장 보러가기

      http://spartacodingclub.shop/wp/vocab
  • 10) API 설계하기

    필요한 기능들을 생각해봅시다. 각 페이지에서는 어떤 일이 일어나야 하나요?

    • 메인 페이지

      1. 단어 검색

        단어가 단어장에 이미 있는 단어인지 검색 → 있으면 하이라이트, 없으면 상세 페이지로 이동

      2. 단어장에 있는 단어를 클릭했을 때 상세 페이지로 이동

    • 상세 페이지
      1. 단어 저장 또는 삭제
      - 단어가 이미 존재하면 삭제 버튼, 아니면 저장 버튼 노출
      - 저장 버튼을 누르면 DB에 저장하고 삭제 버튼으로 바뀜
      - 삭제 버튼을 누르면 DB에서 삭제하고 메인 페이지로 이동
      2. 예문 저장과 삭제
      - 저장된 단어의 경우 예문 칸이 보여지게 하기
      - 예문을 저장하면 목록 맨 아래에 추가
      - 예문에 단어가 포함되지 않으면 얼럿 띄우기
      - 예문을 선택해서 삭제할 수 있음

      https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ee2a90c4-a6ef-497e-9155-38a04390c33c/flowchart.png

02.[세팅하기]프로젝트 세팅

  • 11) 프로젝트 준비 - app.py 준비하기

    • [코드스니펫] - 나만의 단어장 app.py 시작코드

      ```python
      from flask import Flask, render_template, request, jsonify, redirect, url_for
      from pymongo import MongoClient
      import requests
      
      app = Flask(__name__)
      
      client = MongoClient('내AWS아이피', 27017, username="아이디", password="비밀번호")
      db = client.dbsparta_plus_week2
      
      @app.route('/')
      def main():
          # DB에서 저장된 단어 찾아서 HTML에 나타내기
          return render_template("index.html")
      
      @app.route('/detail/<keyword>')
      def detail(keyword):
          # API에서 단어 뜻 찾아서 결과 보내기
          return render_template("detail.html", word=keyword)
      
      @app.route('/api/save_word', methods=['POST'])
      def save_word():
          # 단어 저장하기
          return jsonify({'result': 'success', 'msg': '단어 저장'})
      
      @app.route('/api/delete_word', methods=['POST'])
      def delete_word():
          # 단어 삭제하기
          return jsonify({'result': 'success', 'msg': '단어 삭제'})
      
      if __name__ == '__main__':
          app.run('0.0.0.0', port=5000, debug=True)
      ```

      로컬에서 개발할 때도 AWS 서버에 있는 MongoDB를 바로 연결해서 코딩하면 나중에 배포할 때 DB를 복사해 옮길 필요가 없어 편합니다 😉

  • 12) 프로젝트 준비 - index.html, detail.html 준비하기

  • 13) 프로젝트 준비 - 배너 이미지 준비하기

03.[기능만들기]목록 페이지 - 검색 기능 만들기

  • 25) 단어 검색 기능 만들기

    • 단어를 검색했을 때 이미 저장된 단어인지 알기 위해서 있는 단어 리스트를 만듭니다.

      let words = {{ words|tojson }};
      let word_list = [];
      for (let i = 0; i < words.length; i++) {
          word_list.push(words[i]["word"])
      }
    • 단어를 검색했을 때 단어 리스트에 있는 경우에는 해당 행을 하이라이트하고, 없는 단어일 때는 단어 상세페이지로 넘어가는 기능을 만듭니다.

      function find_word() {
          let word = $("#input-word").val().toLowerCase();
          if (word == "") {
      				// 빈 문자열이면 얼럿
              alert("please write something first :)")
              return
          }
          if (word_list.includes(word)) {
      				// 리스트에 있으면 하이라이트
              $(`#word-${word}`).addClass('highlight').siblings().removeClass('highlight');
              $(`#word-${word}`)[0].scrollIntoView();
          } else {
      				// 리스트에 없으면 상세 페이지로
              window.location.href = `/detail/${word}?status_give=new`
          }
      }
    • 하이라이트된 행은 다음과 같은 CSS로 나타내줍니다.

      tr.highlight > td {
          background-color: #e8344e;
          color: white;
      }
      
      tr.highlight a {
          color: white;
      }

04.[기능만들기]목록 페이지 - 사전에 없는 단어일 때

  • 26) 단어가 존재하지 않을 때 기능 만들기

  • 27) og태그, favicon 넣기

  • 28) 전체 완성 코드

    • app.py

      from flask import Flask, render_template, request, jsonify, redirect, url_for
      from pymongo import MongoClient
      import requests
      
      app = Flask(__name__)
      
      client = MongoClient('mongodb://아이디:비밀번호@내 아이피', 27017)
      db = client.dbsparta_plus_week2
      
      @app.route('/')
      def main():
          msg = request.args.get("msg")
      
          # DB에서 저장된 단어 찾아서 HTML에 나타내기
          words = list(db.words.find({}, {"_id": False}))
          return render_template("index.html", words=words, msg=msg)
      
      @app.route('/detail/<keyword>')
      def detail(keyword):
          # API에서 단어 뜻 찾아서 결과 보내기
          status_receive = request.args.get("status_give", "old")
          r = requests.get(f"https://owlbot.info/api/v4/dictionary/{keyword}",
                           headers={"Authorization": "Token [내 토큰]"})
          if r.status_code != 200:
              return redirect(url_for("main", msg="Word not found in dictionary; Try another word"))
          result = r.json()
          print(result)
          return render_template("detail.html", word=keyword, result=result, status=status_receive)
      
      @app.route('/api/save_word', methods=['POST'])
      def save_word():
          # 단어 저장하기
          word_receive = request.form['word_give']
          definition_receive = request.form['definition_give']
          doc = {"word": word_receive, "definition": definition_receive}
          db.words.insert_one(doc)
          return jsonify({'result': 'success', 'msg': f'word "{word_receive}" saved'})
      
      @app.route('/api/delete_word', methods=['POST'])
      def delete_word():
          # 단어 삭제하기
          word_receive = request.form['word_give']
          db.words.delete_one({"word": word_receive})
          return jsonify({'result': 'success', 'msg': f'word "{word_receive}" deleted'})
      
      if __name__ == '__main__':
          app.run('0.0.0.0', port=5000, debug=True)
    • index.html

      <!DOCTYPE html>
      <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
              <title>Sparta Vocabulary Notebook</title>
              <meta property="og:title" content="Sparta Vocabulary Notebook"/>
              <meta property="og:description" content="mini project for Web Plus"/>
              <meta property="og:image" content="{{ url_for('static', filename='logo_red.png') }}"/>
              <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
              <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
              <!-- Bootstrap CSS -->
              <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
                    integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
                    crossorigin="anonymous">
              <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
      
              <link href='{{ url_for("static", filename="mystyle.css") }}' rel="stylesheet">
              <!-- Optional JavaScript -->
              <!-- jQuery first, then Popper.js, then Bootstrap JS -->
              <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
              <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
                      integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
                      crossorigin="anonymous"></script>
              <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
                      integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
                      crossorigin="anonymous"></script>
              <style>
                  .search-box {
                      width: 70%;
                      margin: 50px auto;
                      max-width: 700px;
                  }
      
                  .table {
                      width: 80%;
                      max-width: 800px;
                      margin: auto;
                      table-layout: fixed;
                  }
      
                  .table th {
                      border-top-style: none;
                  }
      
                  td {
                      background-color: white;
                      text-overflow: ellipsis;
                      overflow: hidden;
                      white-space: nowrap;
                  }
      
                  td > a, a:visited, a:hover, a:active {
                      color: black;
                  }
      
                  tr.highlight > td {
                      background-color: #e8344e;
                      color: white;
                  }
      
                  tr.highlight a {
                      color: white;
                  }
      
                  thead:first-child tr:first-child th:first-child {
                      border-radius: 10px 0 0 0;
                  }
      
                  thead:first-child tr:first-child th:last-child {
                      border-radius: 0 10px 0 0;
                  }
      
                  tbody:last-child tr:last-child td:first-child {
                      border-radius: 0 0 0 10px;
                  }
      
                  tbody:last-child tr:last-child td:last-child {
                      border-radius: 0 0 10px 0;
                  }
              </style>
              <script>
                  {% if msg %}
                      alert("{{ msg }}")
                  {% endif %}
                  let words = {{ words|tojson }};
                  let word_list = [];
                  for (let i = 0; i < words.length; i++) {
                      word_list.push(words[i]["word"])
                  }
      
                  function find_word() {
                      let word = $("#input-word").val().toLowerCase();
                      if (word == "") {
                          alert("please write something first :)")
                          return
                      }
                      if (word_list.includes(word)) {
                          $(`#word-${word}`).addClass('highlight').siblings().removeClass('highlight');
                          $(`#word-${word}`).get(0).scrollIntoView();
                      } else {
                          window.location.href = `/detail/${word}?status_give=new`
                      }
                  }
      
              </script>
          </head>
          <body>
              <div class="wrap">
                  <div class="banner" onclick="window.location.href = '/'">
                  </div>
                  <div class="search-box d-flex justify-content-center">
                      <input id="input-word" class="form-control" style="margin-right: 0.5rem">
                      <button class="btn btn-light" onclick="find_word()"><i class="fa fa-search"></i></button>
                  </div>
                  <table class="table">
                      <thead class="thead-light">
                          <tr>
                              <th scope="col" style="width:30%">WORD</th>
                              <th scope="col">MEANING</th>
      
                          </tr>
                      </thead>
                      <tbody id="tbody-box">
                          {% for word in words %}
                              <tr id="word-{{ word.word }}">
                                  <td><a href="/detail/{{ word.word }}?status_give=old">{{ word.word }}</a></td>
                                  <td>{{ word.definition|safe }}
                                  </td>
                              </tr>
                          {% endfor %}
                      </tbody>
                  </table>
              </div>
          </body>
      </html>
    • detail.html

      <!DOCTYPE html>
      <html lang="en">
          <head>
              <meta charset="UTF-8">
              <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
              <title>Sparta Vocabulary Notebook</title>
              <meta property="og:title" content="Sparta Vocabulary Notebook"/>
              <meta property="og:description" content="mini project for Web Plus"/>
              <meta property="og:image" content="{{ url_for('static', filename='logo_red.png') }}"/>
              <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
              <link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
              <!-- Bootstrap CSS -->
              <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
                    integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
                    crossorigin="anonymous">
              <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
              <link href='{{ url_for("static", filename="mystyle.css") }}' rel="stylesheet">
              <!-- Optional JavaScript -->
              <!-- jQuery first, then Popper.js, then Bootstrap JS -->
              <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
              <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
                      integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
                      crossorigin="anonymous"></script>
              <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
                      integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
                      crossorigin="anonymous"></script>
              <style>
      
                  span.example {
                      color: gray;
                      font-size: 14px;
                  }
      
                  .btn-sparta {
                      color: #fff;
                      background-color: #e8344e;
                      border-color: #e8344e;
                  }
      
                  .btn-outline-sparta {
                      color: #e8344e;
                      background-color: transparent;
                      background-image: none;
                      border-color: #e8344e;
                  }
              </style>
              <script>
                  let word = "{{ word }}"
                  $(document).ready(function () {
                  })
      
                  function save_word() {
                      $.ajax({
                          type: "POST",
                          url: `/api/save_word`,
                          data: {
                              word_give: "{{ word }}",
                              definition_give: "{{ result.definitions[0].definition }}"
                          },
                          success: function (response) {
                              alert(response["msg"])
                              window.location.href = "/detail/{{ word }}?status=old"
                          }
                      });
                  }
      
                  function delete_word() {
                      $.ajax({
                          type: "POST",
                          url: `/api/delete_word`,
                          data: {
                              word_give: '{{ word }}',
                          },
                          success: function (response) {
                              alert(response["msg"])
                              window.location.href = "/"
                          }
                      });
                  }
              </script>
          </head>
          <body>
              <div class="wrap">
                  <div class="banner" onclick="window.location.href = '/'">
                  </div>
                  <div class="container">
                      <div class="d-flex justify-content-between align-items-end">
                          <div>
                              <h1 id="word" style="display: inline;">{{ result.word }}</h1>
                              {% if result.pronunciation %}
                                  <h5 id="pronunciation" style="display: inline;">/{{ result.pronunciation }}/</h5>
                              {% endif %}
                          </div>
                          {% if status=="new" %}
                              <button id="btn-save" class="btn btn-outline-sparta btn-lg" onclick="save_word()"><i
                                      class="fa fa-floppy-o"
                                      aria-hidden="true"></i></button>
                          {% else %}
                              <button id="btn-delete" class="btn btn-sparta btn-lg" onclick="delete_word()"><i
                                      class="fa fa-trash-o"
                                      aria-hidden="true"></i></button>
                          {% endif %}
                      </div>
                      <hr>
                      <div id="definitions">
                          {% set definitions = result.definitions %}
                          {% for definition in definitions %}
                              <div style="padding:10px">
                                  <i>{{ definition.type }}</i>
                                  <br>{{ definition.definition.encode('ascii', 'ignore').decode('utf-8') }}<br>
                                  {% if definition.example %}
                                      <span class="example">{{ definition.example.encode('ascii', 'ignore').decode('utf-8') }}</span>
                                  {% endif %}
                              </div>
                          {% endfor %}
                      </div>
                  </div>
              </div>
          </body>
      </html>
    • mystyle.css

      .wrap {
          background-color: RGBA(232, 52, 78, 0.2);
          min-height: 100vh;
          padding-bottom: 50px;
      }
      
      .banner {
          width: 100%;
          height: 200px;
      
          background-color: white;
          background-image: url('logo_red.png');
          background-position: center;
          background-size: contain;
          background-repeat: no-repeat;
      
          cursor: pointer;
      }
      
      .container {
          width: 80%;
          max-width: 800px;
          margin: 30px auto;
          padding: 20px;
          background-color: white;
      
          border: solid 1px gray;
          border-radius: 10px;
      }

2주차 끝! 앗! 예문 작성기능 만들기 숙제!

2주차 끝 & 숙제 설명

각 단어에 내가 만든 예문을 저장/삭제하는 기능을 만들어봅시다!

  • 예문을 저장/삭제하고 보여주는 기능을 만든 후 AWS 서버에 올리는 것까지가 숙제입니다! 1주차에 올려놓은 일기장은 끄고 올려야겠죠?

  • 어디서 시작해야할지 모르겠다면? 아래 코드들을 복사해놓고 시작해보세요 😉

    • [코드스니펫] - 숙제 시작 코드 HTML

      <div id="examples" class="container">
          <h3 style="text-align: center;margin-bottom:1rem">Write your own sentences!</h3>
          <ul id="example-list">
              <li id="ex-0">This sentence contains the word 'word'.&nbsp;&nbsp;&nbsp;<a
                      href="javascript:delete_ex(0)">delete</a></li>
              <li id="ex-1">I don't like using the MS Word program.&nbsp;&nbsp;&nbsp;<a
                      href="javascript:delete_ex(1)">delete</a></li>
          </ul>
          <div class="d-flex justify-content-between" style="margin-left:20px;">
              <input id="new-example" class="form-control form-control-sm" style="margin-right: 0.5rem">
              <button class="btn btn-outline-secondary btn-sm" onclick="add_ex()">add</button>
          </div>
      </div>
    • [코드스니펫] - 숙제 시작 코드 자바스크립트

      function get_examples() {
          $("#example-list").empty()
          $.ajax({
              type: "GET",
              url: `/api/get_exs?word_give=${word}`,
              data: {},
              success: function (response) {
                  console.log(response)
              }
          });
      }
      
      function add_ex() {
          let new_ex = $('#new-example').val();
          console.log(new_ex)
          $.ajax({
              type: "POST",
              url: `/api/save_ex`,
              data: {
              },
              success: function (response) {
                  console.log(response)
                  get_examples()
              }
          });
      
      }
      
      function delete_ex(i) {
          console.log("deleting", i)
          $.ajax({
              type: "POST",
              url: `/api/delete_ex`,
              data: {
                  word_give: word,
                  number_give: i
              },
              success: function (response) {
                  get_examples()
              }
          });
      }
    • [코드스니펫] - 숙제 시작 코드 파이썬

      @app.route('/api/get_exs', methods=['GET'])
      def get_exs():
          # 예문 가져오기
          return jsonify({'result': 'success'})
      
      @app.route('/api/save_ex', methods=['POST'])
      def save_ex():
          # 예문 저장하기
          return jsonify({'result': 'success'})
      
      @app.route('/api/delete_ex', methods=['POST'])
      def delete_ex():
          # 예문 삭제하기
          return jsonify({'result': 'success'})
  • 힌트

    • 우선 예문이 들어갈 칸을 만들어주세요. 새 단어일 때는 보이지 않고 기존 단어일 때만 나타나야합니다 🙂
    • 변화가 있을 때 페이지 전체를 로딩하지 않고 예문 칸만 새로 채워넣는 방법이 효율적이기 때문에 jinja보다는 ajax를 쓰는 것이 좋습니다.
    • input 칸에 예문을 넣고 저장 버튼을 누르면 1) 예문이 해당 단어를 포함하는지 확인하고 2) POST 요청을 보내 DB에 저장해주세요. examples라는 컬렉션을 따로 만들면 좋겠죠?
    • DB에 저장된 예문들 중 해당 단어에 관한 것만 찾아와서 보여주는 함수를 만듭니다. 페이지가 로딩되었을 때, 새 예문을 저장했을 때, 기존 예문을 삭제했을 때 함수를 실행해서 다시 예문을 보여줍니다.
    • 예문을 삭제할 때 여러 예문 중 어떤 것인지 구분을 해야하기 때문에 각 줄에 id를 부여하는 것이 좋습니다.
    • 이제 예문들이 생겼으니, 단어를 삭제할 때 이 단어에 해당하는 예문들도 같이 지워주어야합니다. 컬렉션에서 조건을 만족하는 여러 도큐먼트를 지울 때는 delete_many()를 사용할 수 있어요.

2주차 수업을 들으며 기존에 알던 지식에 곱하기 2억이 된거 같습니다!
3주차는 어떨지 벌써 기대되네요!!

profile
안녕하십니까

0개의 댓글

관련 채용 정보