1. ๋ฌธ์ œ ์ƒํ™ฉ

ImportError: pycurl: libcurl link-time version (7.79.1) is older than compile-time version (7.85.0)

npm run serve ์‹คํ–‰์‹œ pycurl ๋ฒ„์ „ ๋ฌธ์ œ๋กœ ๋ณด์ด๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด์„œ ํ”„๋กœ์ ํŠธ ์‹คํ–‰์ด ๋˜์ง€ ์•Š์•˜๋‹ค.

 

 

2. ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

๋ฐฉ๋ฒ• 1) pycurl ์žฌ์„ค์น˜ - ์‹คํŒจ

์•„๋ž˜ ๋ฐฉ๋ฒ•์œผ๋กœ pycurl ์žฌ์„ค์น˜๋ฅผ ํ•ด๋ดค์ง€๋งŒ ๊ณ„์† ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋‚ฌ๋‹ค.

brew install curl
brew link curl --force
brew install openssl
export LIBRARY_PATH=/usr/local/opt/openssl/lib
export CPATH=/usr/local/opt/openssl/include
pip --no-cache-dir install pycurl
python -c "import pycurl"

 

๋ฐฉ๋ฒ• 2) npm ๋ฒ„์ „ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ - ์„ฑ๊ณต

๊ฒฐ๊ณผ์ ์œผ๋กœ npm ๋ฒ„์ „์„ ๋‹ค์šด๊ทธ๋ ˆ์ด๋“œ ํ–ˆ๋”๋‹ˆ ํ•ด๊ฒฐ๋๋‹ค!

sudo npm install -g n
sudo n 16.13.2

 

PostgreSQL์— ๋Œ€ํ•œ ๊ณผ์ œ๋ฅผ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์žฅ๊ณ  ํ”„๋กœ์ ํŠธ์— PostgreSQL์„ ์—ฐ๋™ํ•˜์—ฌ ์‚ฌ์šฉํ•ด๊ณ ์ž ํ•œ๋‹ค.

 

๋จผ์ €, PostgreSQL์„ ์„ค์น˜ํ•˜๊ณ  DB๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

๋งฅ(Mac)์— PostgreSQL ์„ค์น˜ + DBeaver ์—ฐ๊ฒฐ

PostgreSQL ์„ค์น˜ 1. ํ„ฐ๋ฏธ๋„์—์„œ brew๋ฅผ ์ด์šฉํ•˜์—ฌ ์„ค์น˜ brew install postgresql 2. ๋ฒ„์ „ ํ™•์ธ postgres -V 3. ์‹œ์ž‘ brew services start postgresql 4. ์ ‘์† psql postgres ์ข…๋ฃŒ brew services stop postgresql DBeaver ์—ฐ๊ฒฐ 1. DBeaver ๋‹ค์šด๋กœ

myminju.tistory.com

 

์™„๋ฃŒ๋˜์—ˆ์œผ๋ฉด Django์— psycopg2๋ฅผ ์„ค์น˜ํ•ด์ค€๋‹ค.

pip install psycopg2

 

์„ค์น˜๊ฐ€ ๋˜์—ˆ์œผ๋ฉด settings.py์˜ DATABASE ํ•ญ๋ชฉ์— ์—ฐ๊ฒฐ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'project',
        'USER': 'root',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',
    }
}

 

๊ทธ ํ›„ ํ„ฐ๋ฏธ๋„์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž…๋ ฅํ•˜๊ณ  ์„œ๋ฒ„ ๊ตฌ๋™์„ ํ™•์ธํ•œ๋‹ค.

python manage.py makemigrations
python manage.py migrate
python manage.py runserver

 

์•„๋ž˜์™€ ๊ฐ™์ด ์žฅ๊ณ  ํ”„๋กœ์ ํŠธ์— ์ž˜ ์—ฐ๋™๋˜์–ด ๋ฐ์ดํ„ฐ๊ฐ€ ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค!

 

 

 

Reference

https://velog.io/@chaeri93/Django-Django์™€-Postgresql-์—ฐ๋™ํ•˜๊ธฐ

๋ฌธ์ œ ์ƒํ™ฉ

Vue๋Š” template ๋‹จ์—์„œ html ์š”์†Œ์™€ component ์š”์†Œ๊ฐ€ ํ˜ผ๋™๋˜์ง€ ์•Š๋„๋ก component ์ด๋ฆ„์„ ๋ณตํ•ฉ์–ด๋กœ ๊ถŒ์žฅํ•œ๋‹ค.

 

 

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

ํ•˜๋‹จ์˜ ์†์„ฑ์„ ํ”„๋กœ์ ํŠธ package.json์˜ rules์— ์ถ”๊ฐ€

 

 

 

๊ณต์‹ Reference

vue/multi-word-component-names

๋ฌธ์ œ ์ƒํ™ฉ

VS Code์—์„œ ํ”„๋กœ์ ํŠธ์˜ ESLint ์„ค์ • ํŒŒ์ผ์„ ์ธ์‹ํ•˜๋Š” ๋ถ€๋ถ„์—์„œ ์—๋Ÿฌ ๋ฐœ์ƒ

 

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

ํ•˜๋‹จ์˜ ์ฝ”๋“œ๋ฅผ VS Code์˜ settings.json์— ์ถ”๊ฐ€

Reactivity

  • ๊ฐ์ฒด์˜ ๋™์ž‘์„ ์žฌ์ •์˜ํ•จ
  • ๋ฐ์ดํ„ฐ์˜ ๋ณ€๊ฒฝ์ด ํ™”๋ฉด์— ๋ฐ”๋กœ ๋ฐ˜์˜๋จ
<div id="app"></div>

<script>
var div = document.querySelector("#app");
var viewModel = {};

// Object.defineProperty(๋Œ€์ƒ ๊ฐ์ฒด, ๊ฐ์ฒด์˜ ์†์„ฑ, {
// ์ •์˜ํ•  ๋‚ด์šฉ
// });

// ์ฆ‰์‹œ ์‹คํ–‰ ํ•จ์ˆ˜
(function () {
    function init() {
        Object.defineProperty(viewModel, "str", {
            get: function () {
                console.log("์ ‘๊ทผ");
            },
            set: function (newValue) {
                console.log("ํ• ๋‹น", newValue);
                render(newValue);
            },
    });
}

    function render(value) {
        div.innerHTML = value;
    }

    init();
})();
</script>

 

์ธ์Šคํ„ด์Šค

์†์„ฑ

new Vue({
    el: ,
    template: ,
    data: ,
    methods: ,
    created: ,
    watch: ,
});

 

์ปดํฌ๋„ŒํŠธ

  • ํ™”๋ฉด์˜ ์˜์—ญ์„ ๊ตฌ๋ถ„ํ•˜์—ฌ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๋Š” ๋ทฐ์˜ ๊ธฐ๋Šฅ
  • ์žฌ์‚ฌ์šฉ์„ฑ์ด ํ–ฅ์ƒ๋˜์–ด ํ™”๋ฉด์„ ๋น ๋ฅด๊ฒŒ ์ œ์ž‘ ๊ฐ€๋Šฅ

 

์ „์—ญ ์ปดํฌ๋„ŒํŠธ

// Vue.component('์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„', ์ปดํฌ๋„ŒํŠธ ๋‚ด์šฉ);
// ์ „์—ญ ์ปดํฌ๋„ŒํŠธ - ๊ฑฐ์˜ ์•ˆ์”€
Vue.component("app-header", {
    template: "<h1>Header</h1>",
});

Vue.component("app-content", {
    template: "<div>content</div>",
});

 

์ง€์—ญ ์ปดํฌ๋„ŒํŠธ

new Vue({
    el: "#app",
    // ์ง€์—ญ ์ปดํฌ๋„ŒํŠธ ๋“ฑ๋ก ๋ฐฉ์‹
    components: {
        // '์ปดํฌ๋„ŒํŠธ ์ด๋ฆ„': ์ปดํฌ๋„ŒํŠธ ๋‚ด์šฉ
        "app-footer": {
            template: "<footer>footer</footer>",
        },
    },
});

 

์ปดํฌ๋„ŒํŠธ์™€ ์ธ์Šคํ„ด์Šค์˜ ๊ด€๊ณ„

  • ์ „์—ญ ์ปดํฌ๋„ŒํŠธ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ณ  components์— ๋„ฃ์–ด์ฃผ์ง€ ์•Š๋”๋ผ๋„ ๋ฐ˜์˜์ด ๋˜์ง€๋งŒ (์ด๋ฏธ ๋“ฑ๋ก์ด ๋˜์–ด ์žˆ์Œ)
  • ์ง€์—ญ ์ปดํฌ๋„ŒํŠธ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ณ  components์— ๋„ฃ์–ด์ฃผ์–ด์•ผ ๋ฐ˜์˜์ด ๋จ

 

์ปดํฌ๋„ŒํŠธ ํ†ต์‹  ๋ฐฉ์‹

 

  • props ์ „๋‹ฌ

 

  • event emit

 

๋ทฐ ๋ผ์šฐํ„ฐ

  • SPA๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

 

์‚ฌ์šฉ ๋ฐฉ๋ฒ•

  • CDN ์ˆœ์„œ ์ฃผ์˜! (vue -> vue router ์ˆœ)
  • npm์œผ๋กœ ์„ค์น˜ํ•  ์ˆ˜๋„ ์žˆ์Œ
<script src="[https://cdn.jsdelivr.net/npm/vue/dist/vue.js](https://cdn.jsdelivr.net/npm/vue/dist/vue.js)"></script>
<script src="[https://unpkg.com/vue-router@3/dist/vue-router.js](https://unpkg.com/vue-router@3/dist/vue-router.js)"></script>

 

์˜ต์…˜

  • routes : ๋ผ์šฐํŒ… ํ•  URL์™€ ์ปดํฌ๋„ŒํŠธ ๊ฐ’ ์ง€์ •
  • mode : URL์˜ ํ•ด์‰ฌ ๊ฐ’ ์ œ๊ฑฐ ์†์„ฑ (mode: history)

 

router-view

  • Vue์˜ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€
  • URL์ด ๋ณ€๊ฒฝ๋˜๋ฉด ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ™”๋ฉด์— ๋ฟŒ๋ ค์ง€๋Š” ์ง€์ ์„ ์ •ํ•จ

  • html์˜ a href ๊ฐ™์€ ๊ธฐ๋Šฅ
  • ํŽ˜์ด์ง€ ์ด๋™

 

axios

  • Vue์—์„œ ๊ถŒ๊ณ ํ•˜๋Š” Promise ๊ธฐ๋ฐ˜์˜ HTTP ํ†ต์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • ๋ฌธ์„œํ™” ์ž˜ ๋˜์–ด ์žˆ๊ณ , API๊ฐ€ ๋‹ค์–‘ํ•จ

 

์„ค์น˜

  • CDN
<script src="[https://unpkg.com/axios/dist/axios.min.js](https://unpkg.com/axios/dist/axios.min.js)"></script>
  • NPM
npm install axios

 

์‚ฌ์šฉ๋ฐฉ๋ฒ•

<div id="app">
  <button v-on:click="fetchData">get data</button>
</div>
new Vue({
  el: '#app',
  methods: {
    fetchData: function() {
      axios.get('https://jsonplaceholder.typicode.com/users/')
        .then(function(response) {
          console.log(response);
        })
        .catch(function(error) {
          console.log(error);
        });
    }
  }
})


get data ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ฝ”๋“œ
์‹คํ–‰ํ•˜๋ฉด ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ์ฝ˜์†”์— ์ถœ๋ ฅ๋จ

 

ํ…œํ”Œ๋ฆฟ

๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ

๋ทฐ ์ธ์Šคํ„ด์Šค์—์„œ ์ •์˜ํ•œ ์†์„ฑ๋“ค์„ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•

<div>{{ message }}</div>
new Vue({
  data: {
    message: 'Hello Vue.js'
  }
})

 

๋””๋ ‰ํ‹ฐ๋ธŒ (v-)

๋ทฐ๋กœ ํ™”๋ฉด์˜ ์š”์†Œ๋ฅผ ๋” ์‰ฝ๊ฒŒ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ๋ฒ•

  • ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋””๋ ‰ํ‹ฐ๋ธŒ
    • v-if
    • v-for
    • v-bind
    • v-on
    • v-model (2-way ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ)

 

watch

ํŠน์ • ๋ฐ์ดํ„ฐ์˜ ๋ณ€ํ™”๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ์ž๋™์œผ๋กœ ํŠน์ • ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์†์„ฑ
๊ฐ’์„ ๊ณ„์† ์ถ”์ , ์ด์ „ ๊ฐ’๊ณผ ๋ฐ”๋€ ๊ฐ’์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ, ๋ฐ์ดํ„ฐ ์š”์ฒญ

new Vue({
  data() {
    return {
      message: 'Hello'
    }
  },
  watch: {
    message: function(value, oldValue) {
      console.log(value);
    }
  }
})

message์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ•  ๋•Œ๋งˆ๋‹ค watch ์†์„ฑ์— ์ •์˜ํ•œ message ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋ฉด์„œ ์ฝ˜์†”์— ๋ณ€ํ•œ ๋ฐ์ดํ„ฐ ์ถœ๋ ฅ

computed

๋ฐ”๋€ ๊ฐ’์— ๋Œ€ํ•ด์„œ ๋ชจ๋ฆ„, ๋น ๋ฆ„, ์บ์‹œ ๊ฐ™์€ ๋Š๋‚Œ, validation์ด๋‚˜ ๊ฐ„๋‹จํ•œ ์—ฐ์‚ฐ ๊ฐ€๋Šฅ, ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ

computed: {
  reverseMessage() {
    return this.message.split('').reverse().join('');
  }
}
<div>{{ reverseMessage }}</div>
  • watch๋ณด๋‹ค computed ์“ฐ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•จ

 

์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ

  • vue-cli๋กœ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑํ›„ App.vue
  • .vue ํŒŒ์ผ์„ ๋ชจ๋‘ ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๋ผ๊ณ  ํ•จ
<!-- .vue ํŒŒ์ผ ๊ตฌ์กฐ -->
<template>
  <!-- html (๋ทฐ ์ปดํฌ๋„ŒํŠธ์˜ ํ‘œํ˜„๋‹จ, ํ…œํ”Œ๋ฆฟ ๋ฌธ๋ฒ•) -->
</template>

<script>
  // ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ (๋ทฐ ์ปดํฌ๋„ŒํŠธ ๋‚ด์šฉ)
</script>

<style>
  /* CSS (๋ทฐ ํ…œํ”Œ๋ฆฟ์˜ ์Šคํƒ€์ผ๋ง) */
</style>

 

๋™์ž‘ ์›๋ฆฌ

  • ์‹ฑ๊ธ€ ํŒŒ์ผ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ทฐ ๋กœ๋”์— ์˜ํ•ด HTML, CSS, JS์™€ ๊ฐ™์€ ์›น ์ž์›์œผ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์‹คํ–‰๋จ
  • ๋ทฐ ๋กœ๋”๋Š” ์›นํŒฉ์˜ ๋กœ๋” ์ข…๋ฅ˜ ์ค‘ ํ•˜๋‚˜์ด๊ณ  ๋ทฐ CLI๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ์Œ

+ Recent posts