<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>logger.info()</title>
        <link>https://velog.io/</link>
        <description>안녕하세요</description>
        <lastBuildDate>Wed, 11 Jan 2023 13:16:43 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. logger.info(). All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/gaeng_man" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[TIL 2/2] 백준 2667 단지번호붙이기(graph) python]]></title>
            <link>https://velog.io/@gaeng_man/TIL-22-%EB%B0%B1%EC%A4%80-2667-%EB%8B%A8%EC%A7%80%EB%B2%88%ED%98%B8%EB%B6%99%EC%9D%B4%EA%B8%B0graph-python</link>
            <guid>https://velog.io/@gaeng_man/TIL-22-%EB%B0%B1%EC%A4%80-2667-%EB%8B%A8%EC%A7%80%EB%B2%88%ED%98%B8%EB%B6%99%EC%9D%B4%EA%B8%B0graph-python</guid>
            <pubDate>Wed, 11 Jan 2023 13:16:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/gaeng_man/post/1f0639c9-798e-4d35-b00e-3f98cb7692bc/image.png" alt=""></p>
<h1 id="설계">설계</h1>
<blockquote>
<p>1번의 하위 항목이 2번의 조건문 아래로 겹치는 것은 구현 할 때,
값이 1이 아니라면 continue로 바꿔서 코드를 조금 더 깔끔하게 바꿨습니다.</p>
</blockquote>
<ol>
<li>전체를 순회<ul>
<li>1의 값이 나온다면, queue 인덱스 삽입, 자신 0으로 치환, dfs시작</li>
</ul>
</li>
<li>dfs<ul>
<li>아파트 개수는 1부터 시작</li>
<li>동서남북 조회<ul>
<li>조건문 row 좌표, col 좌표 각각 0이상 N미만</li>
<li>1의 값이 나온다면 아파트 개수 +1, 자신 0 치환</li>
<li>queue에 현재 인덱스(다음) 삽입</li>
</ul>
</li>
<li>끝난다면 아파트 개수 삽입</li>
</ul>
</li>
<li>출력</li>
</ol>
<h1 id="코드">코드</h1>
<pre><code class="language-python">from collections import deque

queue = deque()
N = int(input())
next_rows = [0, 0, 1, -1]
next_cols = [1, -1, 0, -0]
apts = [list(map(int, input())) for _ in range(N)]
results = []


for row in range(N):
    for col in range(N):
        if apts[row][col] != 1:
            continue

        apts[row][col] = 0
        queue.append([row, col])
        count = 1

        while queue:
            r, c = queue.popleft()
            for i in range(4):
                nr, nc = r + next_rows[i], c + next_cols[i]
                if 0 &lt;= nr &lt; N and 0 &lt;= nc &lt; N and apts[nr][nc] == 1:
                    count += 1
                    apts[nr][nc] = 0
                    queue.append([nr, nc])

        results.append(count)

print(len(results))
print(&#39;\n&#39;.join(map(str, sorted(results))))</code></pre>
<ul>
<li>회고
처음 설계한 그대로 작성해 보기 위해 노력하는데 역시 적다보면 생각하지 못 했던 부분이나 더 좋은 방법이 생각이나는 빈도가 코드를 작성할 때 보다 높은 것 같다.
코드를 적을 때 설계 부분에서 조금씩 고치지만 큰 틀은 바뀌지 않아 좋았다.
어제 처음으로 시도해봤던 그래프 문제는 3시간이 걸려도 시간 초과를 해결하지 못했는데,
두 번째(지금) 문제는 1시간 안 걸렸다^^ 66%이상 줄여버리기<del>(</del>내일은 아마 30분이면 풀 듯?~~)
답을 적고 보면 참 쉬운데 시간이 꽤 걸린게 웃기다 ㅋㅋ</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL 1/2] 백준 2178 미로탐색(BFS) Python, 프로그래머스 게임 맵 최단거리]]></title>
            <link>https://velog.io/@gaeng_man/TIL-12-%EB%B0%B1%EC%A4%80-2178-%EB%AF%B8%EB%A1%9C%ED%83%90%EC%83%89BFS-Python-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B2%8C%EC%9E%84-%EB%A7%B5-%EC%B5%9C%EB%8B%A8%EA%B1%B0%EB%A6%AC</link>
            <guid>https://velog.io/@gaeng_man/TIL-12-%EB%B0%B1%EC%A4%80-2178-%EB%AF%B8%EB%A1%9C%ED%83%90%EC%83%89BFS-Python-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B2%8C%EC%9E%84-%EB%A7%B5-%EC%B5%9C%EB%8B%A8%EA%B1%B0%EB%A6%AC</guid>
            <pubDate>Wed, 11 Jan 2023 11:19:12 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/gaeng_man/post/6697c359-4286-4d11-9692-fb02e468de4f/image.png" alt=""></p>
<h3 id="나의-초기-설계-안-좋은-예시">나의 초기 설계 (안 좋은 예시)</h3>
<ol>
<li><p><a href="https://velog.io/@gaeng_man/TIL-BFS-DFS-%EB%AC%B8%EC%A0%9C%EC%99%80%EC%9D%98-2%EC%8B%9C%EA%B0%84-%EC%9D%B4%EC%83%81%EC%9D%98-%EC%82%AC%ED%88%AC-%ED%9C%B4%EC%A0%84">어제 배운 그래프 형태</a>를 이용해 보려고 했다.</p>
<ol>
<li>행, 열의 값들을 순서대로 0번 부터 행*열-1 까지의 번호를 매김</li>
<li>동서남북 좌표에 조건문을 단다 (-1있거나 행이 행 크기보다 크거나, 열도 마찬가지 등)</li>
<li>통과한 좌표에 행좌표*열 + 열의 값을 넣는다</li>
</ol>
</li>
<li><p>깊이 우선이냐 너비 우선이냐  고민</p>
<ol>
<li>깊이 우선</li>
</ol>
<ul>
<li>도착점에 도달했을 때의 count를 넣어주면 되나</li>
<li>그럼 각 노드에 도달했을 때 count값을 넣어줘야하나</li>
<li>하지만 다른 경로가 더 짧을 수 있는데 조건문 처리를 해줘야해?</li>
<li>너무 별론데? <del>안 틀릴 자신이 없다</del></li>
</ul>
<ol start="2">
<li>너비 우선</li>
</ol>
<ul>
<li>제일 먼저 도달한 경우의 count를 보내면 간단하겠는데?</li>
<li>count는 어떻게 셀까?</li>
<li>도달한 노드의 라인, 그 노드의 level을 파악하면 되겠다.</li>
<li>level은 어떻게 파악하나?</li>
<li>level이 바뀌기 전 임의 값을 끼워 넣어서 세자</li>
</ul>
</li>
<li><p>너비 우선으로 결정</p>
<h3 id="나의-부끄러운-코드">나의 부끄러운 코드</h3>
</li>
</ol>
<ul>
<li>프로그래머스는 시간 초과!</li>
<li>백준에서는 3초라는 놀라운 결과로 통과..사실 상 시간 초과<pre><code class="language-python">height, width = map(int, input().split())
maps = [list(map(int, input())) for _ in range(height)]
</code></pre>
</li>
</ul>
<p>li = [(0, 1), (1, 0), (0, -1), (-1, 0)]
graph = {x : [] for x in range(width<em>height)}
for i in range(width</em>height):
    좌표 = (i//width, i%width)
    if maps[좌표[0]][좌표[1]] == 0:
        continue
    for j in li:
        next_좌표 = (좌표[0]+j[0] , 좌표[1]+j[1])
        if -1 in next_좌표 or width &lt;= next_좌표[1] or height &lt;= next_좌표[0] or maps[next_좌표[0]][next_좌표[1]] == 0:
            continue
        graph[i].append(next_좌표[0]*width + next_좌표[1])</p>
<p>def bfs():
    visited, need_visit = list(), list([0,&#39;x&#39;])
    count = 1</p>
<pre><code>while (len(need_visit) != 1 or need_visit[0] != &#39;x&#39;):
    x = need_visit.pop(0)
    if x == &quot;x&quot;:
        count += 1
        need_visit.append(&#39;x&#39;)
        continue
    if x in visited:
        continue
    if x == width*height-1:
        break
    visited.append(x)
    need_visit.extend(graph[x])
return count</code></pre><p>print(bfs())</p>
<pre><code>### 오답 노트
- 그래프 형태에 묶인 편협한 생각은 이 문제로 끝(~~개념만 배우고 문제를 처음 접해서 그런걸로 ㅎㅎ..~~)
- 아니다 싶은 로직 위에 덧붙이지 말자

### 옳바른 정답 발상 (사견)
- 방문이 필요한 노드의 동서남북 값을 각각 확인하여 1인 경우에만 (자기자신 값 + 1) 값을 대입하고 방문이 필요한 노드로 append
    - 숫자가 대입된 곳은 무조건 최단거리이다.
    - 0은 막힌 곳이며 1초과의 값이면 이미 방문했던 곳이다.
- 도착지점의 값을 출력

#### 수정 코드
```python
from collections import deque

n, m = map(int, input().split())
maps = [ list(map(int, input())) for _ in range(n) ]
dx = [1, -1, 0, 0]
dy = [0, 0, 1, -1]

queue = deque()
count = 0

def bfs(x,y):
    queue.append([x,y])
    while queue:
        x, y = queue.popleft()

        for i in range(4):
            nx, ny = x + dx[i], y + dy[i]
            if 0 &lt;= nx &lt; n and 0 &lt;= ny &lt; m and maps[nx][ny] == 1:
                maps[nx][ny] = maps[x][y] + 1
                queue.append([nx, ny])
    return maps[n-1][m-1]

print(dfs(0,0))</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL 3/3] 동시성 vs 병렬성 그리고 프로세스와  스레드 ]]></title>
            <link>https://velog.io/@gaeng_man/TIL-33-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EB%8F%99%EC%8B%9C%EC%84%B1%EA%B3%BC-%EB%B3%91%EB%A0%AC%EC%84%B1</link>
            <guid>https://velog.io/@gaeng_man/TIL-33-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EB%8F%99%EC%8B%9C%EC%84%B1%EA%B3%BC-%EB%B3%91%EB%A0%AC%EC%84%B1</guid>
            <pubDate>Tue, 10 Jan 2023 14:34:13 GMT</pubDate>
            <description><![CDATA[<h3 id="사전-간단-지식">사전 간단 지식</h3>
<ul>
<li>CPU : 명령어를 해석하고 실행하는 장치</li>
<li>프로그램 : 명령어들의 집합체</li>
<li>메모리<ul>
<li>주메모리 : 램</li>
<li>보조메모리 : HDD SSD</li>
</ul>
</li>
<li>운영 체제 : 컴퓨터 시스템을 운영하고 관리하는 소프트웨어</li>
<li>시스템 버스 : 요소들을 연결해주는 역할</li>
</ul>
<h2 id="프로세스와-스레드">프로세스와 스레드</h2>
<blockquote>
<p>프로세스는 운영체제로부터 자원을 할당받는 작업의 단위이고
스레드는 프로세스 내에서 실행되는 여러 작업의 단위이다.</p>
</blockquote>
<ul>
<li><p>예를 들어서 컴퓨터에게 주어지는 처리 방법과 순서를 기술한 일련의 명령문 집합체인 프로그램을 실행 했을 때, <strong>보조 메모리에 있던 것이 주메모리에 올라와서 작업이 진행</strong>되는 것이다.
=&gt; <strong>프로세스가 생성된다는 의미는 프로그램이 실행된 동적인 상태가 된다는 것이다.</strong></p>
</li>
<li><p>그렇게 된다면 CPU는 프로세스가 해야할 작업을 수행하고, 작업을 수행하는 단위가 스레드인 것이다.</p>
</li>
<li><p>만약 작업을 해야할 작업이 하나이면 싱글 스레드, 여러개면 멀티 스레드이다.</p>
<h3 id="멀티-스레드의-장단점">멀티 스레드의 장단점</h3>
</li>
<li><p>장점 : 멀티 스레드에서 스레드끼리 메모리 공유와 통신이 가능하다; 자원의 낭비를 막고 효율성을 향상할 수 있다.</p>
</li>
<li><p>단점 : 한 스레드에 문제가 생기면 전체 프로세스에 영향을 미친다.</p>
</li>
</ul>
<h2 id="동시성병행성-vs-병렬성">동시성(병행성) vs 병렬성</h2>
<h3 id="동시성concurrency">동시성(concurrency)</h3>
<ul>
<li>한 번에 여러 작업을 동시에 다루는 것을 의미한다(<strong>스위칭을 한다</strong>)</li>
<li>논리적 개념이다. 싱글 스레드(asyncio), 멀티 스레드 적용이 가능하다.<h3 id="병렬성parallelism">병렬성(Parallelism)</h3>
</li>
<li>한 번에 여러 작업을 병렬적으로 처리하는 것을 의미한다(<strong>at the same time</strong>)</li>
<li>멀티 코어, 멀티 스레딩</li>
<li>파이썬에서는 스레드가 병렬성으로 구현될 수 없다. GIL(Global Interpreter Lock), 동시성으로 구현이 돼야한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL 2/3] BFS & DFS, 문제와의 2시간 이상의 사투 (휴전)]]></title>
            <link>https://velog.io/@gaeng_man/TIL-BFS-DFS-%EB%AC%B8%EC%A0%9C%EC%99%80%EC%9D%98-2%EC%8B%9C%EA%B0%84-%EC%9D%B4%EC%83%81%EC%9D%98-%EC%82%AC%ED%88%AC-%ED%9C%B4%EC%A0%84</link>
            <guid>https://velog.io/@gaeng_man/TIL-BFS-DFS-%EB%AC%B8%EC%A0%9C%EC%99%80%EC%9D%98-2%EC%8B%9C%EA%B0%84-%EC%9D%B4%EC%83%81%EC%9D%98-%EC%82%AC%ED%88%AC-%ED%9C%B4%EC%A0%84</guid>
            <pubDate>Tue, 10 Jan 2023 12:26:02 GMT</pubDate>
            <description><![CDATA[<h2 id="bfs--dfs">BFS &amp; DFS</h2>
<ul>
<li>대표적인 그래프 <strong>탐색</strong> 알고리즘<ul>
<li>너비 우선 탐색 (Breadth First Search): 정점들과 같은 레벨에 있는 노드들 (형제 노드들)을 먼저 탐색하는 방식</li>
<li>깊이 우선 탐색 (Depth First Search): 정점의 자식들을 먼저 탐색하는 방식</li>
</ul>
</li>
</ul>
<p><img src="https://iq.opengenus.org/content/images/2020/05/dfs-vs-bfs.gif" alt="">
출처 : <a href="https://iq.opengenus.org/dfs-vs-bfs/">https://iq.opengenus.org/dfs-vs-bfs/</a></p>
<h3 id="파이썬으로-그래프를-표현하는-방법">파이썬으로 그래프를 표현하는 방법</h3>
<ul>
<li>딕셔너리와 리스트 자료 구조를 활용해서 그래프를 표현할 수 있다.<img src="https://www.fun-coding.org/00_Images/bfsgraph.png" width=700>
출처 : https://www.fun-coding.org
```python
graph = dict()

</li>
</ul>
<p>graph[&#39;A&#39;] = [&#39;B&#39;, &#39;C&#39;]
graph[&#39;B&#39;] = [&#39;A&#39;, &#39;D&#39;]
graph[&#39;C&#39;] = [&#39;A&#39;, &#39;G&#39;, &#39;H&#39;, &#39;I&#39;]
graph[&#39;D&#39;] = [&#39;B&#39;, &#39;E&#39;, &#39;F&#39;]
graph[&#39;E&#39;] = [&#39;D&#39;]
graph[&#39;F&#39;] = [&#39;D&#39;]
graph[&#39;G&#39;] = [&#39;C&#39;]
graph[&#39;H&#39;] = [&#39;C&#39;]
graph[&#39;I&#39;] = [&#39;C&#39;, &#39;J&#39;]
graph[&#39;J&#39;] = [&#39;I&#39;]</p>
<pre><code>
### BFS
```python
def bfs(graph, start_node):
    visited, need_visit = list(), list()
    need_visit.append(start_node)

    while need_visit:
        node = need_visit.pop(0)
        if node not in visited:
            visited.append(node)
            need_visit.extend(graph[node])
    return visited</code></pre><h3 id="dfs">DFS</h3>
<pre><code class="language-python">def dfs(graph, start_node):
    visited, need_visit = list(), list()
    need_visit.append(start_node)

    while need_visit:
        node = need_visit.pop()
        if node not in visited:
            visited.append(node)
            need_visit.extend(graph[node])
    return visited</code></pre>
<ul>
<li>회고
BFS와 DFS의 구현은 친절한 파이썬 덕분에 어렵지 않지만 오늘 알고리즘 친구를 만나서 사투를 벌이고는 휴전 상태이다.
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/1844">게임맵 최단거리</a>
30분만 잡아보고 안되면 정답을 보고자 했지만 내 힘으로 풀고 싶어서 20분만 20분만 하다가 2시간 이상이 지났고, 제출 후 정확성은 맞았으나 시간초과가 나서 일단 휴전 협정 후 내일 다시 싸울 예정이당.
부끄러운 나의 코드와 생각은 해결 후 내일 업로드 예정</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL 1/3] getattr, setattr, hasattr, delattr 사용법 & 활용]]></title>
            <link>https://velog.io/@gaeng_man/getattr-setattr-hasattr-delattr-%EC%82%AC%EC%9A%A9%EB%B2%95-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@gaeng_man/getattr-setattr-hasattr-delattr-%EC%82%AC%EC%9A%A9%EB%B2%95-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Tue, 10 Jan 2023 00:06:21 GMT</pubDate>
            <description><![CDATA[<h1 id="getattr-setattr-hasattr-delattr-사용법--활용">getattr, setattr, hasattr, delattr 사용법 &amp; 활용</h1>
<h2 id="getattr--속성값-메서드-가져오기">getattr : 속성값, 메서드 가져오기</h2>
<p><code>getattr(객체, 속성 이름 [, 속성이 없을 때 반환 값])</code></p>
<pre><code class="language-python">getattr(...)
    getattr(object, name[, default]) -&gt; value

    Get a named attribute from an object; getattr(x, &#39;y&#39;) is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn&#39;t exist; without it, an exception is raised in that case.</code></pre>
<h3 id="예제">예제</h3>
<pre><code class="language-python">class 통장:
    def __init__(self, 개설_축하_금액):
        &quot;&quot;&quot;통장 개설!!ㅊㅊ&quot;&quot;&quot;
        self.통장액수 = 개설_축하_금액

    def 입금(self, 입금액):
        self.통장액수 += 입금액

    def 출금(self, 출금액):
        self.통장액수 -= 출금액</code></pre>
<ul>
<li>사용자에게서 입금 출금의 행위를 입력 받고 금액도 입력 받아보겠다.</li>
</ul>
<h4 id="몸이-힘들어질-수도-있는-방법">몸이 힘들어질 수도 있는 방법</h4>
<pre><code class="language-python">테스트_통장 = 통장(5000)
x = input(&#39;입금 or 출금?&#39;) # 입금
y = input(&#39;얼마나?&#39;)
테스트_통장.x(int(y)) # SyntaxError, 테스트_통장.&quot;입금&quot;(int(5000))</code></pre>
<ul>
<li>x는 &quot;입금&quot; 혹은 &quot;출금&quot;으로 들어온다고 했을 때, if문을 사용한다면 아래와 같이 할 수 있을 것이다.</li>
</ul>
<pre><code class="language-python">if x == &#39;입금&#39;:
    return 테스트_통장.입금(int(y))
elif x == &#39;출금&#39;:
    return 테스트_통장.출금(int(y))</code></pre>
<ul>
<li>하지만 입금, 출금만 있는게 아니라 입입금과 출출금 등 새로운 메서드들을 추가한다고 생각하면 if문이 계속 늘어날 것이다.</li>
<li>이렇게 나누는 분기가 명확하다면 getattr을 사용해 보자</li>
</ul>
<h4 id="확장하기-편해지는-방법">확장하기 편해지는 방법</h4>
<pre><code class="language-python">x = input(&#39;입금 or 출금?&#39;) # 입금
y = input(&#39;얼마나?&#39;)
func = getattr(테스트_통장, x) # 테스트_통장.&quot;입금&quot; &gt;&gt;&gt; 테스트_통장.입금
func(int(y))</code></pre>
<h2 id="setattr">setattr()</h2>
<p><code>getattr(객체, 속성 이름, 지정 값)</code></p>
<pre><code class="language-python">setattr(obj, name, value, /)
    Sets the named attribute on the given object to the specified value.

    setattr(x, &#39;y&#39;, v) is equivalent to ``x.y = v&#39;&#39;</code></pre>
<ul>
<li>object에 새로운 속성을 추가하고 값은 value로 줍니다.</li>
</ul>
<h2 id="hasattr">hasattr()</h2>
<p><code>hasattr(객체, 속성 이름)</code></p>
<pre><code class="language-python">hasattr(obj, name, /)
    Return whether the object has an attribute with the given name.

    This is done by calling getattr(obj, name) and catching AttributeError.</code></pre>
<ul>
<li>속성이 있는지 True False로 반환합니다. getattr 혹은 setattr 시에 유효성 검사를 할 수도 있겠죵?</li>
<li><code>if not hasattr(테스트_통장, x): return &quot;입력 제대로!&quot;;</code></li>
</ul>
<h2 id="delattr">delattr()</h2>
<p><code>delattr(객체, 속성 이름)</code></p>
<pre><code class="language-python">delattr(obj, name, /)
    Deletes the named attribute from the given object.

    delattr(x, &#39;y&#39;) is equivalent to ``del x.y&#39;&#39;</code></pre>
<ul>
<li>객체의 속성을 지웁니다.</li>
</ul>
<h1 id="활용하기까리하고-편리하게-개인용">활용하기(까리하고 편리하게, 개인용)</h1>
<p>페이히어 기업과제로 가계부를 만들기를 받았다. django를 사용했고,</p>
<p>지출에 해당하는 것만 구현하면 됐지만, 상세 내용에 수입/지출의 값을 넣고 싶었다. 또한 일별 총 수입/지출의 값을 넣으려 설계했다.</p>
<p>그러기 위해서 상세 내용의 수입/지출 내역을 쓰면 일별 수입/지출 또한 바뀌어야했다.</p>
<p>그래서 생성/삭제 시에 변경되는 값을 바꾸기 위해 아래와 같이 만들었는데 getattr과 setattr을 사용하면 확장성 있게 바뀔 수 있겠다.</p>
<h2 id="바꾸기-전">바꾸기 전</h2>
<pre><code class="language-python">def add_income_expense(self, instance):
    money_type = instance.money_type
    is_expense = True if money_type == &#39;0&#39; else False

    if is_expense:
        instance.day_log.expense += instance.money
    else:
        instance.day_log.income += instance.money

def sub_income_expense(self, instance):
    money_type = instance.money_type
    is_expense = True if money_type == &#39;0&#39; else False

    if is_expense:
        instance.day_log.expense -= instance.money
    else:
        instance.day_log.income -= instance.money
</code></pre>
<h2 id="바꾼-후">바꾼 후</h2>
<pre><code class="language-python">func_dict = {
    &quot;add&quot; : lambda x,y : x+y,
    &quot;sub&quot; : lambda x,y : x-y,
}
money_type = {
    &quot;0&quot; : &quot;expense&quot;,
    &quot;1&quot; : &quot;income&quot;
}

def add_or_sub_income_expense(self, instance, op):

    money_type = instance.money_type
    func = func_dict[op]
    x = getattr(instance.day_log, money_type[money_type])
    money = func(x, instance.money)

    setattr(instance.day_log, income_or_expoense[money_type], money)</code></pre>
<ul>
<li>눈에 한번에 잘 들어오는 것은 바꾸기 전이긴 하다. 하지만 상황에 따라 다르겠지만 확장성은 아래가 더 좋을지도?</li>
</ul>
<h2 id="나아가서">나아가서..</h2>
<ul>
<li>django를 사용하고 있는데 model이나 serializer에서 저장 시 자동적으로 업데이트가 될 수 있게 만들 수 있을건데 뭐가 더 괜찮을지는 생각을 해봐야겠당</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Python Coroutine, 코루틴이란?]]></title>
            <link>https://velog.io/@gaeng_man/TIL-Python-Coroutine-%EC%BD%94%EB%A3%A8%ED%8B%B4%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@gaeng_man/TIL-Python-Coroutine-%EC%BD%94%EB%A3%A8%ED%8B%B4%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Mon, 09 Jan 2023 15:03:10 GMT</pubDate>
            <description><![CDATA[<p>코루틴을 알기 전 몇가지 간단하게(<del>내가 잘 모르니까 ㅋㅋ</del>) cs지식을 짚고 넘어가자</p>
<h3 id="바운드와-블로킹">바운드와 블로킹</h3>
<h4 id="블로킹--바운드에-의해-코드가-멈추게-되는-현상">블로킹 : 바운드에 의해 코드가 멈추게 되는 현상</h4>
<h4 id="cpu-바운드">CPU 바운드</h4>
<ul>
<li>프로그램이 실행될 때 실행 속도가 CPU속도에 의해 제한 됨을 의미</li>
<li>복잡한 수학 수식을 계산할 때(연산을 많이할 때)</li>
</ul>
<h4 id="io-바운드">I/O 바운드</h4>
<ul>
<li>Input/Output 바운드</li>
<li>프로그램이 실행될 때 실행 속도가 I/O에 의해 제한됨을 의미</li>
<li>사용자가 키보드로 숫자를 입력하는 경우 뿐만 아니라, 컴퓨터와 컴퓨터끼리 통신을 할 대에도 I/O 바운드가 발생한다.</li>
</ul>
<h3 id="동기-vs-비동기">동기 vs 비동기</h3>
<h4 id="동기sync">동기(Sync)</h4>
<ul>
<li>코드가 동기적으로 동작한다. =&gt; 코드가 반드시 작성된 순서 그대로 실행된다.</li>
</ul>
<h4 id="비동기async">비동기(Async)</h4>
<ul>
<li>코드가 작성된 순서대로 실행되지 않는다.</li>
</ul>
<p>코루틴은 비동기로 처리된다.</p>
<h2 id="코루틴의-이해">코루틴의 이해</h2>
<h3 id="루틴">루틴</h3>
<ul>
<li>하나의 진입점과 하나의 탈출점이 있는 루틴이다.</li>
<li>루틴이란? 일련의 명령 (코드의 흐름)<ul>
<li>메인 루틴 : 프로그램의 메인 코드의 흐름</li>
<li>서브 루틴 : 보통의 함수나 메소드(메인 루틴을 보조함)</li>
</ul>
</li>
</ul>
<h3 id="코루틴">코루틴</h3>
<ul>
<li>서브 루틴의 일반화된 형태</li>
<li>다양한 진입점과 다양한 탈출점이 있는 루틴이다.(간단하게 다양한 출/입 함수이다)</li>
<li>파이썬에서는 비동기 함수는 코루틴 함수로 만들 수 있다.</li>
</ul>
<h3 id="asyncawait">async/await</h3>
<ul>
<li>코루틴 함수는 async 키워드를 함수 앞에 붙여 사용이 가능하다.</li>
<li>원하는 진입/탈출점에 await 키워드를 붙여 사용한다.</li>
<li>async 함수 밖에서 await 키워드를 사용하고 싶은 경우에는 ayncio 내장 라이브러리를 사용한다.</li>
<li>asyncio.run(함수())</li>
<li>또한 await 키워드 뒤에는 어웨이터블 객체(<strong>coroutine, task, future</strong>)가 와야한다.</li>
</ul>
<h4 id="task">task</h4>
<ul>
<li>코루틴을 동시에 예약하는 데 사용된다.</li>
<li>asyncio.create_task()와 같은 함수를 사용해 테스크로 싸일 때 코루틴은 곧 실행 되도록 자동으로 예약됩니다.</li>
</ul>
<p>예제는 좀 더 숙지 후 올릴 예정</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[23년도 첫 주 회고]]></title>
            <link>https://velog.io/@gaeng_man/23%EB%85%84%EB%8F%84-%EC%B2%AB-%EC%A3%BC-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@gaeng_man/23%EB%85%84%EB%8F%84-%EC%B2%AB-%EC%A3%BC-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 08 Jan 2023 12:56:37 GMT</pubDate>
            <description><![CDATA[<p>작년 12월 30일 캠프가 끝나고 새해 첫 주말이다.
이번 주에 포트폴리오, 이력서를 바삐 쓰고 페이 히어 회사에 이력서를 넣고 기업 과제를 받아서 4일가량 열심히 풀고 제출하니 4개월간 쌓였던 피로와 긴장이 풀린 게 물려 현재 조금 몸이 안 좋아 타이레놀을 하나 먹고 쓰는 중이다ㅋㅋ
지금 지원한 회사에 붙는다면 몹시 기쁘겠지만 안 붙는다 하더라도 개인 기량을 높일 수 있는 기간이 될 테니 불안감은 있겠지만 나름 재밌게 공부하지 않을까 싶다.
공부해야 할 것은 산더미고 배우고 싶은 것도 매우매우 많지만, 이번 달의 대략적인 계획은 이렇다.
인프라에 관한 공부와 알고리즘 복습과 공부하지 못했던 것을 채우면서 비전공자에게 부족한 CS 지식을 채우지 않을까 싶다. django를 더 깊게 파고 fastapi, redis, go 등 배우고 싶은 게 너무 많다. 어느 정도까지 습득을 해야 취업을 하는 것이 적당한지는 모르겠으나 뭐 공부하면서 넣다 보면 되지 않을까 싶다 ㅋㅋ(<del>그전에 재밌는 서비스 만들어서 취업 안 할 수도? ㅋㅋ</del>)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS/TIL] IP와 TCP, UDP]]></title>
            <link>https://velog.io/@gaeng_man/CSTIL-IP%EC%99%80-TCP-UDP</link>
            <guid>https://velog.io/@gaeng_man/CSTIL-IP%EC%99%80-TCP-UDP</guid>
            <pubDate>Wed, 04 Jan 2023 14:01:06 GMT</pubDate>
            <description><![CDATA[<h3 id="ip-internet-protocol">IP (internet protocol)</h3>
<ul>
<li>지정한 IP주소에 데이터 전달</li>
<li>패킷(Packet)이라는 통신 단위로 데이터 전달
<a href="https://ko.wikipedia.org/wiki/%ED%86%B5%EC%8B%A0_%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C">프로토콜이란?</a>
사람과 사람이 통신할때 서로 이해할 수 있는 언어, 공용된 언어를 사용해 전세계 모든 사람과 대화 할수 있다라고 하면, 컴퓨터와 컴퓨터도 서로 이해 할 수 있는 언어, 공용된 언어를 사용 해야 한다는 것인데
이 것이 바로 프로토콜(Protocol) 입니다.</li>
</ul>
<h3 id="ip-패킷-정보">IP 패킷 정보</h3>
<ul>
<li><p>출발 IP, 목적지 Ip, 기타 &amp; 데이터</p>
</li>
<li><p>단점(IP 프로토콜의 한계)</p>
</li>
<li><ol>
<li>비연결성 : 패킷을 받을 대상이 없거나 서비스 불능 상태여도 패킷 전송한다</li>
</ol>
</li>
<li><ol start="2">
<li>비신뢰성 : 중간에 패킷이 사라지거나 순서대로 안올 수 있다.</li>
</ol>
</li>
<li><ol start="3">
<li>프로그램 구분 : 같은 IP를 사용하는 서버에서 통신하는 애플리케이션이 둘 이상일 때 구분 지을 수 없다</li>
</ol>
</li>
</ul>
<h3 id="인터넷-프로토콜-스택의-4계층">인터넷 프로토콜 스택의 4계층</h3>
<ul>
<li>애플리케이션 계층 - HTTP, FTP</li>
<li>전송 계층 - TCP, UDP</li>
<li>인터넷 계층 - IP</li>
<li>네트워크 인터페이스 계층 - 이더넷,</li>
</ul>
<h3 id="tcp-특징">TCP 특징</h3>
<ul>
<li><p>전송 제어 프로토콜 (Transmission Control Protocol)</p>
</li>
<li><p><strong>연결 지향 - TCP 3 way handshake(가상연결)</strong></p>
</li>
<li><p><strong>데이터 전달 보증</strong></p>
</li>
<li><p><strong>순서 보장</strong></p>
</li>
<li><p>신뢰할 수 있는 프로토콜</p>
</li>
<li><p>대부분 TCP 사용</p>
</li>
</ul>
<h4 id="연결-지향-씬-씬엨-엨">연결 지향 (씬 씬엨 엨)</h4>
<ol>
<li>클라이언트에서 먼저 syn 접속 요청을 보내면</li>
<li>서버에서는 ack요청 수락과 함께 syn를 클라이언트에게 보낸다.</li>
<li>클라이언트는 서버에게 ack를 보내고 </li>
<li>데이터를 전송할 수 있게된다. (3에서 데이터 전송 가능)</li>
</ol>
<h4 id="데이터-전달-보증">데이터 전달 보증</h4>
<ol>
<li>데이터 전송</li>
<li>데이터 잘 받았음</li>
</ol>
<h4 id="순서-보장">순서 보장</h4>
<ol>
<li>123 순서로 전송</li>
<li>132 순서로 도착</li>
<li>다시보내 (수정 가능)</li>
</ol>
<h3 id="udp-특징">UDP 특징</h3>
<ul>
<li><p>사용자 데이터그램 프로토콜(User Datagram Protocol)</p>
</li>
<li><p>기능이 거의 없고 <strong>데이터 전달 및 순서가 보장되지 않지만, 단순하고 빠르다.</strong></p>
</li>
<li><p><strong>IP와 거의 같으나 Port와 체크섬</strong> 정도만 추가됐다</p>
</li>
<li><p>애플리케이션에서 추가 작업이 필요하다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[내배캠] 최종 프로젝트 KPT회고]]></title>
            <link>https://velog.io/@gaeng_man/nbc-last-project</link>
            <guid>https://velog.io/@gaeng_man/nbc-last-project</guid>
            <pubDate>Fri, 30 Dec 2022 18:38:34 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/gaeng_man/post/d01a1804-63ea-4835-ace4-5fedbc569443/image.png" alt="">
<img src="https://velog.velcdn.com/images/gaeng_man/post/08ada572-864b-43bd-9dcc-b05e499e80bb/image.png" alt="">
<img src="https://velog.velcdn.com/images/gaeng_man/post/2aabff8b-f41c-4973-9aec-a5d867bc57ed/image.png" alt="">
<img src="https://velog.velcdn.com/images/gaeng_man/post/843ea1d3-ab1b-41f5-9f0f-54876e27be24/image.png" alt=""></p>
<h2 id="뒤풀이-사진">뒤풀이 사진!</h2>
<p><img src="https://velog.velcdn.com/images/gaeng_man/post/0f115777-b7fb-4dff-ac8d-b48b5810dd94/image.png" alt="뒤풀이~!">
<del>팀원분들이 화염병이냐고 놀림ㅋㅋ</del>
다들 술 한 잔.. 그리고 롤링페이퍼를 할까 하다가 오글거리니까 하지 말자로 변경ㅋㅋㅋㅋ</p>
<h2 id="미우나-고우나-우리팀ㅠㅠ">미우나 고우나 우리팀..ㅠㅠ</h2>
<p>처음 준호님 원채님 나, 3명으로 팀 구성이 되고 차례로 민수님, 기훈님, 상훈님이 들어오셨다.
4개월 동안 팀을 변경할 기회는 매우 많았지만 유지하는 쪽으로 항상 마음이 기울었다. 잘하시는 다른 분들과 팀을 해볼 기회도 분명 있었지만 그렇게 하지 않은 이유는 사람이 좋고 책임감도 있었기 때문이다. </p>
<p>항상 좋을 순 없었고 책임감이고 뭐고 내 살길 가버려?!라는 심정이 들 때도 있었다(<del>물론 다들 엄청 잘 하시겠지만 다른 팀에 아련히 있을 팀원들을 생각하니 가슴이 저려서 그건 차마..ㅋㅋㅋ</del>) 그럴 때는 서로 솔직하게 털어 놓음으로써 풀어갈 수 있었다.</p>
<p>기술적으로나 경험으로나 제일 부족한 팀이었을 수 있지만, 우리 팀이 항상 최고라 생각하였습니다.
팀장으로서의 자질이나 실력적으로 부족한 저를 믿고 지지해 주신 팀원분들께 너무나 감사했고 더 도움을 못 드려서 죄송하다는 생각이 들었다.</p>
<p>모두 좋은 분들이기에 어딜 가시던 잘 하실 분이라는 것을 알기에 낸중에 같은 곳에서 근무하며 커피 마시면서 회상하시리라 믿는다. <del>그전에 내가 회사 차려서 스카웃 ㅋㅋ</del></p>
<p>4개월간의 힘들고 재밌었던 동거동락, 막을 내렸다. 하지만 새로운 막이 열리고 이제 진짜 시작인 것 같아 무섭기도 설레기도 한다.</p>
<p>나 또한 잘할 거고 팀원분들도 매우 매우 잘하시리라 믿는다.</p>
<p><span style="font-size:13px"><em>ps. 오늘 모든 포스팅을 velog에 옮겨야하네ㅠ 오히려 좋아~</em></span></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 2022.12.19 ~ 12.25]]></title>
            <link>https://velog.io/@gaeng_man/TIL-2022.12.19-12.25</link>
            <guid>https://velog.io/@gaeng_man/TIL-2022.12.19-12.25</guid>
            <pubDate>Fri, 30 Dec 2022 18:35:44 GMT</pubDate>
            <description><![CDATA[<h1 id="til114일차1219-배포-모드-정리-linux-cp-ft-내배캠">[TIL/114일차/12.19] 배포 모드 정리, linux cp ft. 내배캠</h1>
<ul>
<li>settings.py에 DP_MODE를 설정하여 개발 환경과 배포환경에 맞게 설정해줌.</li>
<li>ec2 postgresql의 볼륨에 media의 default사진이 들어가지 않아서 cp 명령어를 이용하여 복사함.</li>
</ul>
<h1 id="til115일차1220-알림-기능-세팅-ft-내배캠">[TIL/115일차/12.20] 알림 기능 세팅 ft. 내배캠</h1>
<p>async_to_sync를 활용하여 channels_layer를 가져오고 group_send를 통하여 알람 기능도 만들 예정이다.</p>
<pre><code class="language-python">async_to_sync(layer.group_send)(f&#39;alram_{goods.buyer.id}&#39;, {&#39;type&#39;: &#39;chat_message&#39;, &#39;response&#39;: json.dumps({&#39;response_type&#39;: &#39;alram&#39;, &#39;message&#39;: &#39;낙찰됨&#39;})})</code></pre>
<h1 id="til116일차1221-리팩토링-ft-내배캠">[TIL/116일차/12.21] 리팩토링 ft. 내배캠</h1>
<p>팀원 분이 맡아서 하는 부분을 내가 맡게 되면서 기존의 APIView를 ModelViewSet으로 바꾸면서 쿼리를 줄이고 Restfull하게 짜려고 노력해 보았다.</p>
<pre><code class="language-python">from django.db.models import Prefetch

class IsTrader(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        return request.user in [obj.goods.seller, obj.goods.buyer]

class ChatViewSet(ModelViewSet):
    &quot;&quot;&quot;
    리스트 &#39;list&#39; 요청이 오면 채팅방 리스트를 보내줍니다.
    특정 방의 요청이 &#39;retrive&#39; 오면 채팅방의 채팅들을 보내줍니다.
    &quot;&quot;&quot;
    permission_classes = [IsTrader,]

    def get_permissions(self):
        if self.action == &#39;list&#39;:
            return [permissions.IsAuthenticated(),]
        return super(ChatViewSet, self).get_permissions()

    def get_serializer_class(self):
        if self.action == &#39;list&#39;:
            return TradeInfoSerializer
        elif self.action == &#39;retrive&#39;:
            return TradeMessageSerializer
        else:
            return None
    def get_serializer_context(self):
        # print(self.request.data)
        return {
            &#39;request&#39;: self.request,
            &#39;format&#39;: self.format_kwarg,
            &#39;view&#39;: self,
            &#39;action&#39; : self.action
        }
    def get_queryset(self):
        print(dir(Goods.objects.first()))
        user_id = self.request.user.id
        if self.action == &#39;list&#39;:
            goods = Goods.objects.filter(status = False, buyer__isnull=False).filter( Q(buyer_id = user_id) | Q(seller_id = user_id)).select_related(&#39;seller&#39;, &#39;buyer&#39;, &#39;trade_room&#39;).prefetch_related(&#39;trade_room__trademessage&#39;)
            return goods
        elif self.action == &#39;retrive&#39;:
            return TradeChatRoom.objects.all()
        else:
            return None</code></pre>
<h1 id="til117일차1222-채팅-view-리팩토링-생각-정리-ft-내배캠">[TIL/117일차/12.22] 채팅 view 리팩토링 생각 정리 ft. 내배캠</h1>
<ul>
<li>설계 로직</li>
</ul>
<p>채팅방 리스트 큰 틀 : 내가 구매 혹은 판매 물품의 거래 채팅방을 최근 업데이트 된 날짜로 나열하여 보여준다.</p>
<ol>
<li><p>물풀의 객체들에서 상태 값은 False(경매가 끝남), 구매자는 있어야한다.</p>
</li>
<li><p>물품의 구매자 혹은 판매자가 자신이어여야만 한다.</p>
</li>
<li><p>쿼리 수를 줄이기 위해,prefetch 와 select를 사용한다.</p>
</li>
<li><p>Goods의 trade_room은 TradeCahtRoom을 외래키로 참조한다(원래는 oto이 맞다).</p>
<ul>
<li>annotate를 사용하여 trade_room의 업데이트 날짜 trade_room__updated_at을 가져와</li>
<li>updated_at의 임의의 컬럼을 만들어 정렬해 준다.</li>
</ul>
</li>
<li><p>선택된 Goods의 객체들을 TradeInfoSerializer에 넣어서 보낸다.</p>
<ul>
<li>wait_cnt : 쿼리 요청을 한 번 더 보내지 않기 위해 반복문을 통하여 길이를 구함</li>
<li>image : 첫 번째 사진의 url만 필요함. first()를 쓰지 않은 것은 위와 같이  쿼리 요청을 안하기 위하여</li>
<li>last_message : 인덱싱을 통하여 마지막 요소를 가져오나, Negative인덱싱은 불가능하여 (전체 길이 -1)을 try except 구문을 사용하여 담아</li>
</ul>
</li>
</ol>
<p>개별 채팅 방 틀 : 요청자의 권한을 파악, 메시지 읽음 처리</p>
<ol>
<li>특정 Goods 객체의 판매자 혹은 구매자를 판별</li>
<li>해당 객체의 메시지들을 가져와 내가 작성한 것들을 제외한 메시지를 읽음 처리함.
줌</li>
</ol>
<h1 id="til118일차1223-참여자-피드백-ft-내배캠">[TIL/118일차/12.23] 참여자 피드백 ft. 내배캠</h1>
<h3 id="참여자-피드백">참여자 피드백</h3>
<ul>
<li>입찰 내역, 채팅 내역, 참여자들 정보들</li>
<li>경매 시작 알람, 낙찰 알람, 입찰 경쟁 알람</li>
</ul>
<h1 id="wil-17주차-ft-내배캠">[WIL] 17주차 ft. 내배캠</h1>
<h3 id="회고">회고</h3>
<ul>
<li>프로젝트 리팩토링 기간이기도 하며 다음 주면 캠프가 끝난다.</li>
<li>재밌기도 하고 힘들기도 했다.</li>
<li>돌이켜 보면 4개월 동안 필수적인 일을 제외하면 밖으로 나갔던 날은 손으로 꼽는 것 같다. ㅋㅋㅋ</li>
<li>운동도 안 해버려서 피폐해진 감이 없잖아 있는데 곧 끝나니 운동도 다시 시작하며 힘차게 취업 전선에 뛰어들자!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Serializer 객체 접근 & 게시글에 포함 된 여러장의 이미지를 serializer로 저장하기]]></title>
            <link>https://velog.io/@gaeng_man/Serializer-%EA%B0%9D%EC%B2%B4-%EC%A0%91%EA%B7%BC-%EA%B2%8C%EC%8B%9C%EA%B8%80%EC%97%90-%ED%8F%AC%ED%95%A8-%EB%90%9C-%EC%97%AC%EB%9F%AC%EC%9E%A5%EC%9D%98-%EC%9D%B4%EB%AF%B8%EC%A7%80%EB%A5%BC-serializer%EB%A1%9C-%EC%A0%80%EC%9E%A5%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@gaeng_man/Serializer-%EA%B0%9D%EC%B2%B4-%EC%A0%91%EA%B7%BC-%EA%B2%8C%EC%8B%9C%EA%B8%80%EC%97%90-%ED%8F%AC%ED%95%A8-%EB%90%9C-%EC%97%AC%EB%9F%AC%EC%9E%A5%EC%9D%98-%EC%9D%B4%EB%AF%B8%EC%A7%80%EB%A5%BC-serializer%EB%A1%9C-%EC%A0%80%EC%9E%A5%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 30 Dec 2022 18:34:54 GMT</pubDate>
            <description><![CDATA[<h2 id="serializer-객체-접근할-수-있는-3가지">Serializer 객체 접근할 수 있는 3가지</h2>
<h3 id="initial_data">initial_data</h3>
<ul>
<li>유효성 검사를 하기 전에 필드에 접근할 수 있습니다.<pre><code class="language-python">serializer = serializer_class(data = request.data)
serializer.initial_data[&#39;필드&#39;] = 값 or 필드 값을 이용할 수 있음</code></pre>
</li>
</ul>
<h3 id="validated_data">validated_data</h3>
<ul>
<li>유효성 검사를 통과한 필드에 접근 할 수 있다.<pre><code class="language-python">serializer = serializer_class(data = request.data)
if serializer.is_valid():
  serializer.validated_data[&#39;필드&#39;] = 값
  serializer.save()</code></pre>
</li>
</ul>
<h3 id="data">data</h3>
<ul>
<li>유효성 검사를 통과하고 save된 필드에 접근할 수 있다.<pre><code class="language-python">serializer = serializer_class(data=request.data)
if serializer.is_valid():
  serializer.save()
  serializer.data[&#39;필드&#39;]</code></pre>
</li>
</ul>
<h2 id="게시글에-포함-된-여러장의-이미지-serializer로-저장하기">게시글에 포함 된 여러장의 이미지 serializer로 저장하기</h2>
<h3 id="modelspy">models.py</h3>
<pre><code class="language-python">
class Goods(models.Model):
    class Meta:
        db_table = &#39;Goods&#39;

    seller = models.ForeignKey(User, on_delete=models.CASCADE, related_name=&#39;sell_goods&#39;)
    title = models.CharField(max_length=256)
    content = models.TextField()



class GoodsImage(models.Model):
    goods = models.ForeignKey(Goods, on_delete=models.CASCADE)
    image = models.ImageField(upload_to=&#39;goods/&#39;)
</code></pre>
<p>예시로 상품 모델이 있고 상품 이미지 모델을 만들었다.
상품에는 여러개의 이미지를 포함시키기 위해 상품이미지 모델을 분리 시켜서 상품을 참조하도록 하였다.</p>
<h3 id="serializerspy">serializers.py</h3>
<pre><code class="language-python">

class GoodsImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = GoodsImage
        fields = [&#39;image&#39;,]


class GoodsDetailSerializer(serializers.ModelSerializer):
    seller = serializers.SerializerMethodField()
    goodsimage_set = GoodsImageSerializer(many=True, read_only = True)

    # images = serializers.SerializerMethodField()
    # def get_images(self, obj):
        # return GoodsImageSerializer(obj.goodsimage_set.all(), many = True).data

    def get_seller(self, obj):
        return obj.seller.username

    class Meta:
         model = Goods
         fields = &#39;__all__&#39;</code></pre>
<p>상품 이미지 모델에서 상품을 참조하기 때문에 상품에서 역참조 시 related_name이 설정되어 있지 않다면 모델_set 필드로 사용하면 되고, 상품 이미지 시리얼 라이저를 통하여 many=True, read_only=True값을 주어서 이미지의 주소 값을 가져올 수 있다. </p>
<p>(주석처럼 SerializerMethodField를 사용해 주어도 된다.)</p>
<h3 id="viewspy">views.py</h3>
<pre><code class="language-python">
class GoodsView(ModelViewSet):

    queryset = Goods.objects.prefetch_related(&#39;goodsimage_set&#39;).select_related(&#39;seller&#39;).all()
    serializer_class = GoodsDetailSerializer
    permission_classes = [IsAuthorOrReadOnly,]

    def get_permissions(self):
        if self.action == &#39;create&#39;:
            return [permissions.IsAuthenticated(),]
        return super(GoodsView, self).get_permissions()


    def create(self, request, *args, **kwargs):

        serializer = self.get_serializer(data=request.data)

        images = serializer.initial_data.pop(&#39;goodsimage_set&#39;)  [1]
        images = [{&#39;image&#39; : image} for image in images]        [2]

        serializer.is_valid(raise_exception=True)
        obj = self.perform_create(serializer)               [3]

        image_serializer = GoodsImageSerializer(data = images, many = True) [4]
        image_serializer.is_valid(raise_exception=True) [4]
        image_serializer.save(goods = obj)  [5]

        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)


    def perform_create(self, serializer):
        return serializer.save(seller_id = self.request.user.id) # save()메서드는 생성된 object를 반환해 주기 때문에 오버라이딩하였다</code></pre>
<p>모델 뷰셋을 사용하였는데 여기에서 중요한 것만 짚겠다.</p>
<p>post요청이 왔을 때 create메서드를 오바라이딩 하였다</p>
<ul>
<li>[1] 유효성 검사를 통하기 전 데이터(initial_data)에서 이미지 필드의 값들을 빼온다</li>
<li>[2] 1번에서 빼온 이미지 데이터를 {&#39;필드값&#39; : 이미지값} serializer양식에 맞춰준다</li>
<li>[3] 글 양식에서 이미지를 제외한 데이터를 serializer를 통해서 저장하고 객체를 가져온다.</li>
<li>[4] 2번에서 양식을 맞춰준 이미지 데이터들을 시리얼 라이저에 넣어 유효성 검사를 한다.</li>
<li>[5] 어떤 상품을 바라보는지 3번에서의 값을 저장시켜준다.</li>
</ul>
<p><del>request.data에서 빼와서 사용을 해도 되지만 serializer에서 접근을 하고 싶은 마음에 검색하여 사용했다.</del> </p>
<p>serializer클래서 내부에서 가공되지 않은 상태의 데이터를 사용하기 위해서 initial_data를 사용하는 것으로 판단을 하였다. context에 데이터를 넘겨주어도 되지만 여기서는 굳이 그렇게 안 하고 view에서 처리하였다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 2022.12.12 ~ 12.18]]></title>
            <link>https://velog.io/@gaeng_man/TIL-2022.12.12-12.18</link>
            <guid>https://velog.io/@gaeng_man/TIL-2022.12.12-12.18</guid>
            <pubDate>Fri, 30 Dec 2022 18:32:07 GMT</pubDate>
            <description><![CDATA[<h1 id="til107일차1212-프론트-로직--ui--pr보내기-전에-자알-보자-ㅎ-ft-내배캠">[TIL/107일차/12.12] 프론트 로직 &amp; UI &amp; PR보내기 전에 자알 보자 ㅎ; ft. 내배캠</h1>
<p><img src="https://velog.velcdn.com/images/gaeng_man/post/edb26973-405f-4b67-ba45-6e5024d85302/image.png" alt=""></p>
<p>프로젝트 마무리 단계에 있어서 스타일이나 자잘한 수정을 보고 있다. 디자인에 감각이 없기도하고 JS를 검색을 통해서 바로바로 적용을 하면서 하다보니 코드가 정갈하지 않은 점과 백엔드에 집중하지 못하는 점이 아쉽지만, 출시할 생각에 모든 재미있다. </p>
<ul>
<li>오늘 실수한 것은 pr을 보낼 때 개인 정보가 담겨있는 것을 보내 지울 수는 없다는 것을 알았다.</li>
<li>비밀키를 서비스에서 지우면 되지만 나의 번호가 남아있어 조금은 찝찝하긴 하다.</li>
<li>심지어 내가 팀원분께 그거 보내지 말라고 했는데도 없이 보냈다고 착각을 하여서 머지를 해버렸당 ㅎㅎ.. 잘 확인하자!</li>
</ul>
<h1 id="til107일차1213-q객체-ft-내배캠">[TIL/107일차/12.13] Q객체 ft. 내배캠</h1>
<p>Q객체 장고 orm 쿼리문처럼 쓰고 싶을 때 사용할 수 있다.
and의 경우에는 &amp;가 있다.
&amp;=는 where의 and조건이고
|=는 wherer의 or조건이다.</p>
<pre><code class="language-python">q = Q(status = True) | Q(status = None)
recommend_goods = self.get_queryset().filter(q).annotate(participants_count = Count(&#39;auctionparticipant&#39;)).order_by(&#39;-participants_count&#39;)[:10]
serializer = GoodsListSerializer(recommend_goods, many = True, context = self.get_serializer_context())</code></pre>
<h1 id="til108일차1214-프로젝트-발표-준비-백엔드-배포-시작-ft-내배캠">[TIL/108일차/12.14] 프로젝트 발표 준비 백엔드 배포 시작 ft. 내배캠</h1>
<p>회고</p>
<ul>
<li>docker와 nginx를 미리 공부하지 않고 배포를 시작하는 단계다 보니 꽤 힘들었다. 기본적인 백엔들 배포는 가능하더라도 다른 컨테이너 간의 연결이라던가 기본적인 것이 많이 안들어왔다. 그래서 여기에 조금 더 공부를 해보면 좋고 재밌을 것 같다는 생각을 했다. 또한 발표를 위해서 준비할 것이 꽤 많아 집중을 하느라 TIL에 조금 소홀하긴하다.</li>
</ul>
<h1 id="til109일차1215-프로젝트-중간-발표--회고-ft-내배캠">[TIL/109일차/12.15] 프로젝트 중간 발표 &amp; 회고 ft. 내배캠</h1>
<p><img src="https://velog.velcdn.com/images/gaeng_man/post/f3d5dfcb-c6b5-4353-b9bd-ac378667e602/image.png" alt=""></p>
<p>프로젝트 중간 발표가 끝나고 이제 배포와 피드백을 받고 프로젝트를 보완하고 발전하려는 작업을 남기고 있었고 더 나은 협업을 위해서 깃허브의 프로젝트를 활용하자고 하였다. 서로의 이슈에 대해서 논의할 수 있고 얼마나 진행됐는지와 어떤 방식으로하면 좋을 지에 대해서 논의 할 수 있는 것이 마음에 들어서 제안을 하였고 다행스럽게도 좋게 봐주셨다.</p>
<h1 id="til110일차1216-annotate-ft-내배캠">[TIL/110일차/12.16] annotate ft. 내배캠</h1>
<p>annotate를 활용한다면 기존에 있던 컬럼에 내가 원하는 컬럼을 추가하여 볼 수 있다.
나는 두개의 테이블에서 다른 하나를 참조하는 개수에 대해서 알아내기 위해서 사용하였고 좀 더 자게한 것은 추후에 포스팅할 계획이다.</p>
<pre><code class="language-python">q = Q(status = True) | Q(status = None)
recommend_goods = self.get_queryset().filter(q).annotate(participants_count = Count(&#39;auctionparticipant&#39;)).order_by(&#39;-participants_count&#39;)[:10]
serializer = GoodsListSerializer(recommend_goods, many = True, context = self.get_serializer_context())

return Response(data = serializer.data, status=status.HTTP_200_OK)</code></pre>
<p>이것을 사용함으로써 원래 Goods query_set에는 참여자 수라는 컬럼이 없었지만 annotate를 사용하여 참여자 수를 가져올 수 있었다.</p>
<h1 id="wil-내일-배움-캠프-16주차">[WIL] 내일 배움 캠프 16주차</h1>
<h3 id="주간-회고">주간 회고</h3>
<p>나는 코딩을 처음 했을 때 너무너무 못 한것을 알기에 지금 처음 하시는 분들에 대해서 존경하는 부분들이 꽤 많다. 그래서 존중하고 더 알려드리려고 하는 부분들이 있다. 하지만 시간이 갈 수록 내가 배려하는 부분에 대해서 당연하게 생각하시고 더 바라시게 되는 것 같다. 이것 또한 내가 잘 못한 것이라고 생각한다. 이를 바로 잡아야하고 이런 일이 다시 생기게 되면 안될 것 같다는 생각을 한다. 배우는 인생.. 재밌다. 이래서 협업을 해봐야 하는 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 2022.12.05 ~ 12.11]]></title>
            <link>https://velog.io/@gaeng_man/TIL-2022.12.05-12.11</link>
            <guid>https://velog.io/@gaeng_man/TIL-2022.12.05-12.11</guid>
            <pubDate>Fri, 30 Dec 2022 18:29:53 GMT</pubDate>
            <description><![CDATA[<h1 id="til100일차1205-bulk_create-시-유의사항-ft-내배캠">[TIL/100일차/12.05] bulk_create() 시 유의사항 ft. 내배캠</h1>
<h2 id="bulk_create-시-유의사항">bulk_create() 시 유의사항</h2>
<p>이미 정해져있는 인스턴스를 저장해야하기 때문에 Model() 인스턴스를 직접 만들어주어 pk값이 지정되게 한다</p>
<p>기존</p>
<pre><code class="language-python">instance = Goods.objects.create(**validated_data)
image_set = self.context[&#39;request&#39;].FILES.getlist(&#39;goodsimage_set&#39;)
image_list = [{&#39;goods&#39; : instance, &#39;image&#39; : image}  for image in image_set]
GoodsImage.objects.bulk_create(image_list)</code></pre>
<p>변경 후</p>
<pre><code class="language-python">instance = Goods.objects.create(**validated_data)
image_set = self.context[&#39;request&#39;].FILES.getlist(&#39;goodsimage_set&#39;)
image_list = [GoodsImage(goods = instance, image = image) for image in image_set]
GoodsImage.objects.bulk_create(image_list)</code></pre>
<p><strong><a href="https://stackoverflow.com/questions/57220088/dict-object-has-no-attribute-pk-when-using-django-bulk-create-function">&#39;dict&#39; object has no attribute &#39;pk&#39; when using Django bulk_create() function</a></strong></p>
<h1 id="til101일차1206-cssjs-타이머-만들기-django-image-validate-ft-내배캠">[TIL/101일차/12.06] CSS/JS 타이머 만들기, Django image validate ft. 내배캠</h1>
<h2 id="타이머-만들기">타이머 만들기</h2>
<pre><code class="language-html">&lt;div class=&quot;pie-timer&quot; style=&quot;box-shadow: 0 2px 5px 0px;&quot;&gt;
    &lt;div id=&quot;center-timer&quot;&gt;&lt;/div&gt;
&lt;/div&gt;</code></pre>
<pre><code class="language-css">.pie-timer {
            position: relative;
            display: inline-block;
            width: 200px;
            height: 200px;
            border-radius: 50%;
            transition: 0.3s;
        }

        #center-timer {
            background: #fff;
            display: block;
            position: absolute;
            top: 50%;
            left: 50%;
            width: 190px;
            height: 190px;
            border-radius: 50%;
            text-align: center;
            line-height: 100px;
            font-size: 20px;
            transform: translate(-50%, -50%);
        }</code></pre>
<pre><code class="language-js">async function startTimer(time) {

    let totalSecond = time

    let x = setInterval(function () {
        let min = parseInt(totalSecond / 60)
        let sec = totalSecond % 60
        let perTime = totalSecond / (60 * 20) * 100
        let percolor = perTime &lt;= 10 ? &#39;red&#39; : [&#39;blue&#39;, &#39;blue&#39;, &#39;purple&#39;] [parseInt(perTime / 40)] // 테두리 색상 설정

        document.getElementById(&#39;center-timer&#39;).innerHTML = min + &quot;분&quot; + sec + &quot;초&quot;;
        $(&#39;.pie-timer&#39;).css({
            &quot;background&quot;: &quot;conic-gradient(&quot; + percolor + &quot; 0% &quot; + perTime + &quot;%, #ffffff &quot; + perTime + &quot;% 100%)&quot;
        });
        totalSecond--;

        if (totalSecond &lt; 0) {
            clearInterval(x);
            document.getElementById(&#39;center-timer&#39;).innerHTML = &#39;종료&#39;;
        }
    }, 1000);
}</code></pre>
<h2 id="django-이미지-확장자-유효성-검사">Django 이미지 확장자 유효성 검사</h2>
<pre><code class="language-python">from django.core.validators import validate_image_file_extension

class GoodsImage(models.Model):
    goods = models.ForeignKey(Goods, on_delete=models.CASCADE)
    image = models.ImageField(upload_to=&#39;goods/&#39;,validators=[validate_image_file_extension])</code></pre>
<h1 id="til102일차1207-프로젝트-프론트엔드-로직--ui-백엔드-개인-경고-메시지-경매-참여-인원-저장-로직-ft-내배캠">[TIL/102일차/12.07] 프로젝트 프론트엔드 로직 &amp; UI, 백엔드 개인 경고 메시지, 경매 참여 인원 저장 로직 ft. 내배캠</h1>
<ul>
<li><p>오늘 한 일</p>
<ul>
<li>프로젝트 프론트엔드 로직 &amp; UI</li>
<li>백엔드 개인 경고 메시지</li>
<li>경매 참여 인원 저장 로직</li>
<li>전 기수 취업자 면담</li>
<li>팀원 코드 병합</li>
</ul>
</li>
<li><p>회고</p>
<ul>
<li>시중에 내놓았을 때, 사용자들이 편하고 올바르게 사용을 할 수 있게끔. 로직을 세세하게</li>
<li>짜는 것이 재밌지만 전반적인 진행률도 신경을 써야한다.</li>
<li>백엔드에 집중하면 좋긴하지만 프론트엔드를 통해 리프레쉬도 돼서 낫밷이기도 하다.(<del>좀 많이 시간이 걸리는 것은 함정</del>)</li>
<li>힘들지만 재밌다. 배포할 생각에 설레버려 ㅋㅋ 파이팅</li>
</ul>
</li>
</ul>
<h1 id="til103일차1208-백엔드-리팩토링--회원-프론트-로직--ui-ft-내배캠">[TIL/103일차/12.08] 백엔드 리팩토링 &amp; 회원 프론트 로직 &amp; UI ft. 내배캠</h1>
<ul>
<li>오늘 한 일<ul>
<li>백엔드 리팩토링 : APIView에서 ViewSet으로 바꿔 코드를 줄임</li>
<li>회원 인증과 관련된 프론트 UI와 로직 구현</li>
</ul>
</li>
</ul>
<h1 id="til104일차1209-channels-asgi-import-error-js-confirm-truefalse-ft-내배캠">[TIL/104일차/12.09] channels ASGI import error, Js confirm true/false ft. 내배캠</h1>
<ul>
<li>ASGI import error가 난 경우에는 경로가 확실하고 설정이 잘 된 경우 웹소켓을 다루는 파일에서(consumer.py 등) import한 라이브러리를 잘 확인해 보아야합니다.</li>
</ul>
<pre><code class="language-js">&lt;script&gt;
    if (!confirm(&quot;확인(예) 또는 취소(아니오)를 선택해주세요.&quot;)) {
        // 취소(아니오) 버튼 클릭 시 이벤트
    } else {
        // 확인(예) 버튼 클릭 시 이벤트
    }
&lt;/script&gt;</code></pre>
<h1 id="wil-내일-배움-캠프-15주차-ft-내배캠">[WIL] 내일 배움 캠프 15주차 ft. 내배캠</h1>
<ul>
<li>회고<ul>
<li>마지막 최종 프로젝트를 진행하고 있는게 신기하면서도, 불안, 기쁨, 힘듦 여러가지의 감정이 느껴진다. 백엔드를 더 딥하게 파고 싶지만 프론트 없이 프로젝트를 하다보니 그 부분은 어려운 점은 아쉽지만 캠프가 끝나고도 이력서를 넣으면서 공부할 생각에 뭔가 설레기도 한다. 프로젝트 파이팅!</li>
</ul>
</li>
</ul>
<p><del>블로그를 야무지게 채울 생각에 셀렘 가득 ㅎㅋ</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django/Python django-crontab 일정 주기로 함수 실행하기]]></title>
            <link>https://velog.io/@gaeng_man/DjangoPython-django-crontab-%EC%9D%BC%EC%A0%95-%EC%A3%BC%EA%B8%B0%EB%A1%9C-%ED%95%A8%EC%88%98-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@gaeng_man/DjangoPython-django-crontab-%EC%9D%BC%EC%A0%95-%EC%A3%BC%EA%B8%B0%EB%A1%9C-%ED%95%A8%EC%88%98-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 30 Dec 2022 18:29:04 GMT</pubDate>
            <description><![CDATA[<h2 id="django-crontab이란">django-crontab이란?</h2>
<ul>
<li>서버를 실행하고 주기적으로 함수를 실행해야할 경우 필요한 라이브러리이다.</li>
</ul>
<ol>
<li>django-crontab 설치</li>
</ol>
<p><code>pip install django-crontab</code></p>
<ol start="2">
<li><p>settings.py 앱 추가
settings.py</p>
<pre><code class="language-python">INSTALLED_APPS = [
 .
 .
 &#39;django_crontab&#39;,
 .
 .
]</code></pre>
</li>
<li><p>앱 하위에 cron.py 생성 후 원하는 함수 구현</p>
<pre><code class="language-python">def crontab_hello():
 print(&#39;hello&#39;)</code></pre>
</li>
<li><p>settings.py 설정하기</p>
<pre><code class="language-python">CRONJOBS = [
 (&#39;* * * * *&#39;, &#39;study_group.cron.crontab_penalty_student&#39;, &#39;&gt;&gt; &#39;+os.path.join(BASE_DIR, &#39;stady/log/cron.log&#39;)),
]</code></pre>
</li>
</ol>
<ul>
<li>매분 실행하고 프로젝트/폴드/로그파일 경로를 설정하여 로그를 확인할 수 있다.
<a href="https://crontab.guru/#*_*_*_*_*">crontab 시간 설정 웹 사이트</a></li>
</ul>
<ol start="5">
<li>명령어</li>
</ol>
<ul>
<li>보기
<code>python manage.py crontab show</code></li>
<li>추가
<code>python manage.py crontab add</code></li>
<li>삭제
<code>python manage.py crontab remove</code></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 2022.11.28 ~ 12.04]]></title>
            <link>https://velog.io/@gaeng_man/TIL-2022.11.28-12.04</link>
            <guid>https://velog.io/@gaeng_man/TIL-2022.11.28-12.04</guid>
            <pubDate>Fri, 30 Dec 2022 18:26:15 GMT</pubDate>
            <description><![CDATA[<h1 id="til93일차1128-프로젝트-발표--팀-kpt-회고-ft-내배캠">[TIL/93일차/11.28] 프로젝트 발표 &amp; 팀 KPT 회고 ft. 내배캠</h1>
<h3 id="팀-회고">팀 회고</h3>
<ul>
<li><p>느낀점:</p>
<ul>
<li>원채님 : 팀원 모두가 맡을 역할을 잘 소화함</li>
<li>민수님 : 팀이 좋은 방향으로 가고있다는 것을 느낌</li>
<li>기훈님 : 아직 많이 부족하지만 방향성을 찾을 것 같다.</li>
<li>준호님 : 딥러닝 torch를 너무 몰라서 아쉽고 백엔드에 집중을 못 한 것이 조금 아쉽다.</li>
<li>나 : 이전부터 생각해야할 것들이 꽤 많아 조금 지치는 프로젝트였지만 극복하는 것도 꽤 좋았다.</li>
</ul>
</li>
<li><p>Keep:</p>
<ul>
<li>기훈님 : 회의시간을 서로 잘 조율하여 누락없이 소통</li>
<li>민수님 : 오전 오후 회의가 유지하기</li>
<li>준호님 : 오늘의 공부 내용 및 문제 출제 발표 시간 갖기</li>
<li>원채님 : 프로젝트의 연계성 유연성</li>
<li>나 : 문제 내고 풀기</li>
</ul>
</li>
<li><p>문제점:</p>
<ul>
<li>준호님 : 코드 정리를 시기를 찾기 힘든 것</li>
<li>기훈님 : 식사를 제때 하지 못 하는 것</li>
<li>원채님 : 개인적인 목표를 완벽히 이루지는 못 함</li>
<li>민수님 : 회의 때 참여가 좀 더 필요하다. 의견을 잘 내자.</li>
<li>나 : 진행상황을 좀 더 나누자</li>
</ul>
</li>
<li><p>시도점 :</p>
<ul>
<li>민수님 : 커밋 많이 남기기, 이슈 적기</li>
<li>준호님 : 모두 깃 잘 활용하기</li>
<li>원채님 : 변수 이름 잘 쓰기, 진행상황 잘 소통하기</li>
<li>나 : 문서 작성과 설계를 꼼꼼하게 정하고 이행하기</li>
</ul>
</li>
</ul>
<h1 id="til94일차1129-깃허브-리드미-정리-포트폴리오-이력서-특강-ft-내배캠">[TIL/94일차/11.29] 깃허브 리드미 정리, 포트폴리오 이력서 특강 ft. 내배캠</h1>
<h3 id="이력서에서-중요한-것">이력서에서 중요한 것</h3>
<ul>
<li>문제 해결 능력,,,추가 예정</li>
</ul>
<h1 id="til95일차1130-프로젝트핸즈업-프로젝트-컨셉-구상-와이어-프레임-erd-api-구상-ft-내배캠">[TIL/95일차/11.30] 프로젝트(핸즈업) 프로젝트 컨셉 구상, 와이어 프레임, ERD, API 구상 ft. 내배캠</h1>
<h1 id="til96일차1201-django-channels-ft-내배캠">[TIL/96일차/12.01] django-channels ft. 내배캠</h1>
<h3 id="한-것">한 것</h3>
<ul>
<li>프로젝트 뼈대 작업, 팀 관련 작업, 티맥스 채용 설명회</li>
<li>channels-channels 장고 채널스를 통해 웹 소캣을 사용하여 채팅기능을 구현했다. 자세한 내용은 주말에 쓰도록 해야지</li>
</ul>
<p><a href="https://channels.readthedocs.io/en/stable/">django-channels 공식문서</a></p>
<h1 id="til97일차1202-serializer-객체-접근-ft-내배캠">[TIL/97일차/12.02] serializer 객체 접근 ft. 내배캠</h1>
<h3 id="initial_data">initial_data</h3>
<ul>
<li>유효성 검사를 하기 전에 필드에 접근할 수 있습니다.<pre><code class="language-python">serializer = serializer_class(data = request.data)
serializer.initial_data[&#39;필드&#39;] = 값 or 필드 값을 이용할 수 있음</code></pre>
</li>
</ul>
<h3 id="validated_data">validated_data</h3>
<ul>
<li>유효성 검사를 통과한 필드에 접근 할 수 있다.<pre><code class="language-python">serializer = serializer_class(data = request.data)
if serializer.is_valid():
  serializer.validated_data[&#39;필드&#39;] = 값
  serializer.save()</code></pre>
</li>
</ul>
<h3 id="data">data</h3>
<ul>
<li>유효성 검사를 통과하고 save된 필드에 접근할 수 있다.<pre><code class="language-python">serializer = serializer_class(data=request.data)
if serializer.is_valid():
  serializer.save()
  serializer.data[&#39;필드&#39;]</code></pre>
</li>
</ul>
<h1 id="wil-14주차">[WIL] 14주차</h1>
<h3 id="이번-주에-대표적으로-한것">이번 주에 대표적으로 한것</h3>
<ul>
<li>최종 프로젝트 구상 (아이디어, 컨셉, 와이어 프레임, api 등)</li>
<li>Channels를 통한 채팅 구현</li>
<li>viewset활용한 백엔드 구현</li>
</ul>
<h3 id="회고">회고</h3>
<ul>
<li>새로운 주제의 흥미로운 프로젝트를 시작하니 너무나 재밌다. 백엔드를 파면 팔수록 알아야할 것은 쌓여가지만 알아가는 재미가 쏠쏠하지 싶다.</li>
</ul>
<h3 id="다음-주에-할-것">다음 주에 할 것</h3>
<p>알고리즘, 프로젝트 백, 프론트, 사용자 인증 구현</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 2022.11.21 ~ 11.27]]></title>
            <link>https://velog.io/@gaeng_man/TIL-2022.11.21-11.27</link>
            <guid>https://velog.io/@gaeng_man/TIL-2022.11.21-11.27</guid>
            <pubDate>Fri, 30 Dec 2022 18:25:51 GMT</pubDate>
            <description><![CDATA[<h1 id="til86일차1121-django-bulk-ft-내배캠">[TIL/86일차/11.21] Django bulk ft. 내배캠</h1>
<h2 id="bulk_update--bulk_create">bulk_update &amp; bulk_create</h2>
<ul>
<li>.save()요청 시 쿼리요청을 보내게 되는데, 한꺼번에 많은 양의 쿼리를 요청하면 느려지게 된다. 그럴 때는 bulk_를 사용하여 효율적으로 저장을 할 수 있다.</li>
</ul>
<p><code>모델.objects.bulk_update(배열, [컬럼들])</code></p>
<pre><code class="language-python">stuies = []
.
.
.
Study.objects.bulk_update(stuies, [&quot;week_money&quot;])</code></pre>
<h1 id="til87일차1122-sting을-json으로--json을-string으로-변환하기-ft-내배캠">[TIL/87일차/11.22] sting을 json으로 , json을 string으로 변환하기 ft. 내배캠</h1>
<p>json을 string으로 변환하기</p>
<p><code>JSON.stringify(딕셔너리)</code></p>
<p>string을 json으로 변환하기</p>
<p><code>JSON.parse(json형태인문자열)</code></p>
<h1 id="til88일차1123-js-상대-날짜-똑똑하게-표현하기-ft-timeago">[TIL/88일차/11.23] js 상대 날짜 똑똑하게 표현하기 ft. timeago</h1>
<ul>
<li>timeago CDN 받기<pre><code class="language-html">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.6.7/jquery.timeago.min.js&quot;&gt;&lt;/script&gt;</code></pre>
</li>
<li>한국 시간으로 원한다면?<pre><code class="language-html">&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.6.5/locales/jquery.timeago.ko.js&quot;&gt;&lt;/script&gt;</code></pre>
</li>
<li>날짜 시간을 로딩 후 .timeago() 실행하여 나타내 주기!</li>
</ul>
<pre><code class="language-html">&lt;time class=&quot;timeago&quot; datetime=&quot;${time}&quot;&gt;&lt;/time&gt;</code></pre>
<pre><code class="language-js">$(&quot;time.timeago&quot;).timeago();</code></pre>
<p><a href="https://github.com/rmm5t/jquery-timeago">참조-깃헙</a></p>
<h1 id="til89일차1124-mac-git-에러-xcrun-error-invalid-active-developer-path-ft-내배캠">[TIL/89일차/11.24] Mac git 에러 xcrun: error: invalid active developer path ft. 내배캠</h1>
<h3 id="맥업데이트-후-명령어-에러-해결하기">맥업데이트 후 명령어 에러 해결하기</h3>
<p><code>xcode-select --install</code></p>
<h1 id="til90일차1125-js-삼항-연산자-ft-내배캠">[TIL/90일차/11.25] JS 삼항 연산자 ft. 내배캠</h1>
<h3 id="자바스크립트-삼항-연산자">자바스크립트 삼항 연산자</h3>
<p><code>condition ? exprIfTrue : exprIfFalse</code></p>
<p>조건? 참일 때 : 거짓일 때</p>
<pre><code class="language-js">function example(…) {
    return condition1 ? value1
         : condition2 ? value2
         : condition3 ? value3
         : value4;
}</code></pre>
<h1 id="wil-13주차">[WIL] 13주차</h1>
<h3 id="이번-주에-대표적으로-한것">이번 주에 대표적으로 한것</h3>
<ul>
<li>Docker</li>
<li>프로젝트</li>
</ul>
<h3 id="회고">회고</h3>
<ul>
<li>아직 도커에 익숙하지 않아서 배포를 원활하게 못 한 느낌이 있다. 최종 프로젝트에는 좀 더 공부를 하고 잘 적용할 것이다.</li>
</ul>
<h3 id="다음-주에-할-것">다음 주에 할 것</h3>
<p>프로젝트 구상과 진행</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL 2022.11.14 ~ 11.20]]></title>
            <link>https://velog.io/@gaeng_man/TIL-2022.11.14-11.20</link>
            <guid>https://velog.io/@gaeng_man/TIL-2022.11.14-11.20</guid>
            <pubDate>Fri, 30 Dec 2022 18:25:22 GMT</pubDate>
            <description><![CDATA[<h1 id="til79일차1114-docker-opencv-설정-ft-내배캠">[TIL/79일차/11.14] Docker Opencv 설정 ft. 내배캠</h1>
<h2 id="importerror-libglso1-cannot-open-shared-object-file-no-such-file-or-directory">ImportError: libGL.so.1: cannot open shared object file: No such file or directory</h2>
<p>ubuntu22.04.1에서 파이썬 3.10.8 이미지에 opencv를 설치하고 실행을 하는데 아래와 같은 에러가 났다.</p>
<p><code>ImportError: libGL.so.1: cannot open shared object file: No such file or directory</code></p>
<p>찾아보니 libgl1-mesa-glx라는 것이 설치가 안됐기 때문이고</p>
<p>해결 방법은</p>
<p>이미지 빌드하는 파일인 Dockerfile에 설치하는 구문을 추가해 주면 된다.</p>
<pre><code class="language-shell">RUN apt-get update
RUN apt-get -y install libgl1-mesa-glx</code></pre>
<h2 id="ubuntu-버전-확인">ubuntu 버전 확인</h2>
<p><code>$ lsb_release -a</code></p>
<h1 id="til80일차1115-프로젝트-구상-drf살짝-ft-내배캠">[TIL/80일차/11.15] 프로젝트 구상, drf살짝 ft. 내배캠</h1>
<p>프로젝트 기능에 대한 회의, 아이디어 구상과 와이어 프레임, 정책을 생각하는 하루였고 drf에 대하여 약간 공부하는 하루였습니다.</p>
<h1 id="til81일차1116-generics-retrieveapiview-ft-내배캠">[TIL/81일차/11.16] Generics RetrieveAPIView ft. 내배캠</h1>
<h2 id="url-파라미터-두-개-이상-사용하기">url 파라미터 두 개 이상 사용하기</h2>
<ul>
<li>파라미터의 이름이 pk이가(미확) 아니거나 두 개 이상일 경우 특정 인스턴스를 가져올 수 있는 방법에 대해 고민해 보고 찾아봤습니다.</li>
</ul>
<p><strong><em>결론은 self.kwargs에 저장된 것을 활용하면 됨</em></strong></p>
<p>예시, 특정 모델의 인스턴스를 가져오고 싶을 때 get_object를 오버라이딩하여 가져오는 경우</p>
<pre><code class="language-python">def get_object(self):
    return MyModel.objects.get(foo = self.kwargs[&quot;foo&quot;], bar = self.kwargs[&quot;bar&quot;])</code></pre>
<h1 id="til82일차1117-algorithm-drf-listcreateview-ft-내배캠">[TIL/82일차/11.17] Algorithm, DRF ListCreateView ft. 내배캠</h1>
<h2 id="python-len함수는-어떻게-o1의-시간-복잡도를-가질까">python len()함수는 어떻게 O(1)의 시간 복잡도를 가질까?</h2>
<ul>
<li>len()은 __ len __()을 호출한다. (마크다운 언어로 __ 띄움)</li>
<li>__ len __()은 카운터로 작동하며 데이터가 정의되고 저장되면 자동적으로 증가한다.
결과적으로 길이를 가져오라는 것 대신 이미 저장된 value값을 가지고 오는 것이다.</li>
</ul>
<h2 id="algorithm-회고">algorithm 회고</h2>
<p><a href="https://github.com/KimGyeongMin-KR/algoritm/tree/main/rabbit-week-3">토끼반 알고리즘 10문제</a></p>
<ul>
<li>짧게 생각하고 오만함이 차고 넘쳐 까불다가 오히려 시간을 더 써버렸다.</li>
<li>하지만 맞왜틀이 아닌 틀왜맞을 찾았다. 반례를 등록하고 싶은데 프로그래머스에는 있지는 않는 것 같다.</li>
<li>쉬운 풀이가 있음에도 돌아가서 나자신에게 아쉬웠다<del>(성능은 좀 나으니까 정신 승리, 아무나 그렇다고 해줘ㅠ)</del></li>
<li>화나지만 그래도 뿌듯하고 짜증나지만 재밌다. 나 자신에게 화가나</li>
</ul>
<h1 id="til83일차1118-django-쿼리셋-로깅하기-ft-내배캠">[TIL/83일차/11.18] Django 쿼리셋 로깅하기 ft. 내배캠</h1>
<h2 id="로깅이란">로깅이란?</h2>
<ul>
<li>정보를 제공하는 일련의 기록인 로그(log)를 생성하도록 시스템을 작성하는 활동.</li>
</ul>
<p>settings.py</p>
<pre><code class="language-python">LOGGING = {
    &#39;version&#39;: 1,    #logging 버젼
    &#39;disable_existing_loggers&#39;: False, # 원래 있던 로깅들을 그래도 냅둠 # 만약 True면 못쓴다는 거겠죠? ㅎ
    &#39;handlers&#39;: {                    # 로깅 메세지에서 일어나는 일을 결정하는 녀석이라고 장고공식문서에 나와있는데, 아직 무슨말인지는 저도 모르겠네요 ㅎㅎ 
        &#39;console&#39;: {
            &#39;level&#39;: &#39;DEBUG&#39;,
            &#39;class&#39;: &#39;logging.StreamHandler&#39;,
        }
    },
    &#39;loggers&#39;: {                # 로깅을 console에 띄울지 ... 다른데 띄울지 그냥 DEBUG용으로 레벨을 설정할 수 도있고, 
        &#39;django.db.backends&#39;: {
            &#39;handlers&#39;: [&#39;console&#39;],
            &#39;level&#39;: &#39;DEBUG&#39;,
        },
    }
}</code></pre>
<h1 id="til84일차1119-django-crontab-ft-내배캠">[TIL/84일차/11.19] django-crontab ft. 내배캠</h1>
<h2 id="django-crontab이란">django-crontab이란?</h2>
<ul>
<li>서버를 실행하고 주기적으로 함수를 실행해야할 경우 필요한 라이브러리이다.</li>
</ul>
<ol>
<li><p>django-crontab
<code>pip install django-crontab</code></p>
</li>
<li><p>settings.py 앱 추가
settings.py</p>
<pre><code class="language-python">INSTALLED_APPS = [
 .
 .
 &#39;django_crontab&#39;,
 .
 .
]</code></pre>
</li>
<li><p>앱 하위에 cron.py 생성 후 원하는 함수 구현</p>
<pre><code class="language-python">def crontab_hello():
 print(&#39;hello&#39;)</code></pre>
</li>
<li><p>settings.py 설정하기</p>
<pre><code class="language-python">CRONJOBS = [
 (&#39;* * * * *&#39;, &#39;study_group.cron.crontab_penalty_student&#39;, &#39;&gt;&gt; &#39;+os.path.join(BASE_DIR, &#39;stady/log/cron.log&#39;)),
]</code></pre>
</li>
</ol>
<ul>
<li>매분 실행하고 프로젝트/폴드/로그파일 경로를 설정하여 로그를 확인할 수 있다.
(crontab 시간 설정 웹 사이트)[<a href="https://crontab.guru/#*_*_*_*_*%5D">https://crontab.guru/#*_*_*_*_*]</a></li>
</ul>
<h1 id="wil-12주차-내일-배움-캠프-12주차-ft-내배캠">[WIL/ 12주차] 내일 배움 캠프 12주차 ft. 내배캠</h1>
<h3 id="이번-주에-대표적으로-한것">이번 주에 대표적으로 한것</h3>
<ul>
<li>Docker</li>
<li>프로젝트 구상</li>
<li>drf generics viewset(살짝)</li>
<li>알고리즘<h3 id="회고">회고</h3>
</li>
</ul>
<p>느낌적으로 새롭게 배우는 것이 많은 한 주였다. 무언가를 많이 만들기보다는 조금씩 만들며 개념을 다지는 주였다. 알고리즘을 하면서 정답으로 가는 길을 돌아가곤 하는데 잘 짠 코드를 보면 감탄도 나오고 나에 대한 분노도 조금 느끼나 좌절하지 않고 더 잘쓰기 위해서 노력하자는 마음이 든다. DRX의 꺾이지 않는 마음 ㅋ</p>
<h3 id="다음-주에-할-것">다음 주에 할 것</h3>
<p>프로젝트 진행, 배포, 리팩토링, 보완</p>
<p>알고리즘</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[pandas 기초! (value_counts()!, set_option(), columns, info(), describe(), values!!, drop()!, index)]]></title>
            <link>https://velog.io/@gaeng_man/pandas-%EA%B8%B0%EC%B4%88-valuecounts-setoption-columns-info-describe-values-drop-index</link>
            <guid>https://velog.io/@gaeng_man/pandas-%EA%B8%B0%EC%B4%88-valuecounts-setoption-columns-info-describe-values-drop-index</guid>
            <pubDate>Fri, 30 Dec 2022 18:24:05 GMT</pubDate>
            <description><![CDATA[<p><strong>read_csv()</strong></p>
<p>read_csv()를 이용하여 csv파일을 편리하게 DataFrame으로 로딩합니다. 
read_csv()의 sep인자를 콤마(,)가 아닌 다른 분리자로 변경하여 다른 유형의 파일도 로드가 가능합니다. </p>
<pre><code class="language-python">import pandas as pd
titanic_df = pd.read_csv(&#39;titanic_train.csv&#39;)</code></pre>
<p><strong><em>head() tail()</em></strong>
맨 앞 또는 맨 뒤부터 데이터를 가져올 수 있다. 기본 값은 5</p>
<pre><code class="language-python">titanic_df.head()</code></pre>
<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

<pre><code>.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}</code></pre><p></style></p>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: center;">
      <th></th>
      <th>PassengerId</th>
      <th>Survived</th>
      <th>Pclass</th>
      <th>Name</th>
      <th>Sex</th>
      <th>Age</th>
      <th>SibSp</th>
      <th>Parch</th>
      <th>Ticket</th>
      <th>Fare</th>
      <th>Cabin</th>
      <th>Embarked</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1</td>
      <td>0</td>
      <td>3</td>
      <td>Braund, Mr. Owen Harris</td>
      <td>male</td>
      <td>22.0</td>
      <td>1</td>
      <td>0</td>
      <td>A/5 21171</td>
      <td>7.2500</td>
      <td>NaN</td>
      <td>S</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2</td>
      <td>1</td>
      <td>1</td>
      <td>Cumings, Mrs. John Bradley (Florence Briggs Th...</td>
      <td>female</td>
      <td>38.0</td>
      <td>1</td>
      <td>0</td>
      <td>PC 17599</td>
      <td>71.2833</td>
      <td>C85</td>
      <td>C</td>
    </tr>
    <tr>
      <th>2</th>
      <td>3</td>
      <td>1</td>
      <td>3</td>
      <td>Heikkinen, Miss. Laina</td>
      <td>female</td>
      <td>26.0</td>
      <td>0</td>
      <td>0</td>
      <td>STON/O2. 3101282</td>
      <td>7.9250</td>
      <td>NaN</td>
      <td>S</td>
    </tr>
    <tr>
      <th>3</th>
      <td>4</td>
      <td>1</td>
      <td>1</td>
      <td>Futrelle, Mrs. Jacques Heath (Lily May Peel)</td>
      <td>female</td>
      <td>35.0</td>
      <td>1</td>
      <td>0</td>
      <td>113803</td>
      <td>53.1000</td>
      <td>C123</td>
      <td>S</td>
    </tr>
    <tr>
      <th>4</th>
      <td>5</td>
      <td>0</td>
      <td>3</td>
      <td>Allen, Mr. William Henry</td>
      <td>male</td>
      <td>35.0</td>
      <td>0</td>
      <td>0</td>
      <td>373450</td>
      <td>8.0500</td>
      <td>NaN</td>
      <td>S</td>
    </tr>
  </tbody>
</table>
</div>



<p><strong><em>set_option()</em></strong></p>
<pre><code class="language-python">pd.set_option(&#39;display.max_rows&#39;, 1000) # 행 개수
pd.set_option(&#39;display.max_colwidth&#39;, 100) # 컬럼 글자 너비
pd.set_option(&#39;display.max_columns&#39;, 100) # 컬럼 개수</code></pre>
<h2 id="dataframe의-생성">DataFrame의 생성</h2>
<pre><code class="language-python">dic1 = {&#39;Name&#39;: [&#39;Chulmin&#39;, &#39;Eunkyung&#39;,&#39;Jinwoong&#39;,&#39;Soobeom&#39;],
        &#39;Year&#39;: [2011, 2016, 2015, 2015],
        &#39;Gender&#39;: [&#39;Male&#39;, &#39;Female&#39;, &#39;Male&#39;, &#39;Male&#39;]
       }
# 딕셔너리를 DataFrame으로 변환
data_df = pd.DataFrame(dic1)
print(data_df)
print(&quot;#&quot;*30)

# 새로운 컬럼명을 추가
data_df = pd.DataFrame(dic1, columns=[&quot;Name&quot;, &quot;Year&quot;, &quot;Gender&quot;, &quot;Age&quot;])
print(data_df)
print(&quot;#&quot;*30)

# 인덱스를 새로운 값으로 할당. 
data_df = pd.DataFrame(dic1, index=[&#39;one&#39;,&#39;two&#39;,&#39;three&#39;,&#39;four&#39;])
print(data_df)
print(&quot;#&quot;*30)</code></pre>
<pre><code>       Name  Year  Gender
0   Chulmin  2011    Male
1  Eunkyung  2016  Female
2  Jinwoong  2015    Male
3   Soobeom  2015    Male
##############################
       Name  Year  Gender  Age
0   Chulmin  2011    Male  NaN
1  Eunkyung  2016  Female  NaN
2  Jinwoong  2015    Male  NaN
3   Soobeom  2015    Male  NaN
##############################
           Name  Year  Gender
one     Chulmin  2011    Male
two    Eunkyung  2016  Female
three  Jinwoong  2015    Male
four    Soobeom  2015    Male
##############################</code></pre><p>columns, index, values</p>
<pre><code class="language-python">print(&quot;columns:&quot;,titanic_df.columns)
print(&quot;index:&quot;,titanic_df.index)
print(&quot;index value:&quot;, titanic_df.head().index.values)</code></pre>
<pre><code>columns: Index([&#39;PassengerId&#39;, &#39;Survived&#39;, &#39;Pclass&#39;, &#39;Name&#39;, &#39;Sex&#39;, &#39;Age&#39;, &#39;SibSp&#39;,
       &#39;Parch&#39;, &#39;Ticket&#39;, &#39;Fare&#39;, &#39;Cabin&#39;, &#39;Embarked&#39;],
      dtype=&#39;object&#39;)
index: RangeIndex(start=0, stop=891, step=1)
index value: [0 1 2 3 4]</code></pre><p><strong>info()</strong></p>
<p>DataFrame내의 컬럼명, 데이터 타입, Null건수, 데이터 건수 정보를 제공합니다.</p>
<pre><code class="language-python">titanic_df.info()</code></pre>
<pre><code>&lt;class &#39;pandas.core.frame.DataFrame&#39;&gt;
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB</code></pre><p><strong>describe()</strong></p>
<p>데이터값들의 평균,표준편차,4분위 분포도를 제공합니다. 숫자형 컬럼들에 대해서 해당 정보를 제공합니다.</p>
<pre><code class="language-python">titanic_df.describe()</code></pre>
<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

<pre><code>.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}</code></pre><p></style></p>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>PassengerId</th>
      <th>Survived</th>
      <th>Pclass</th>
      <th>Age</th>
      <th>SibSp</th>
      <th>Parch</th>
      <th>Fare</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>count</th>
      <td>891.000000</td>
      <td>891.000000</td>
      <td>891.000000</td>
      <td>714.000000</td>
      <td>891.000000</td>
      <td>891.000000</td>
      <td>891.000000</td>
    </tr>
    <tr>
      <th>mean</th>
      <td>446.000000</td>
      <td>0.383838</td>
      <td>2.308642</td>
      <td>29.699118</td>
      <td>0.523008</td>
      <td>0.381594</td>
      <td>32.204208</td>
    </tr>
    <tr>
      <th>std</th>
      <td>257.353842</td>
      <td>0.486592</td>
      <td>0.836071</td>
      <td>14.526497</td>
      <td>1.102743</td>
      <td>0.806057</td>
      <td>49.693429</td>
    </tr>
    <tr>
      <th>min</th>
      <td>1.000000</td>
      <td>0.000000</td>
      <td>1.000000</td>
      <td>0.420000</td>
      <td>0.000000</td>
      <td>0.000000</td>
      <td>0.000000</td>
    </tr>
    <tr>
      <th>25%</th>
      <td>223.500000</td>
      <td>0.000000</td>
      <td>2.000000</td>
      <td>20.125000</td>
      <td>0.000000</td>
      <td>0.000000</td>
      <td>7.910400</td>
    </tr>
    <tr>
      <th>50%</th>
      <td>446.000000</td>
      <td>0.000000</td>
      <td>3.000000</td>
      <td>28.000000</td>
      <td>0.000000</td>
      <td>0.000000</td>
      <td>14.454200</td>
    </tr>
    <tr>
      <th>75%</th>
      <td>668.500000</td>
      <td>1.000000</td>
      <td>3.000000</td>
      <td>38.000000</td>
      <td>1.000000</td>
      <td>0.000000</td>
      <td>31.000000</td>
    </tr>
    <tr>
      <th>max</th>
      <td>891.000000</td>
      <td>1.000000</td>
      <td>3.000000</td>
      <td>80.000000</td>
      <td>8.000000</td>
      <td>6.000000</td>
      <td>512.329200</td>
    </tr>
  </tbody>
</table>
</div>



<p><strong>value_counts()</strong></p>
<p>동일한 개별 데이터 값이 몇건이 있는지 정보를 제공합니다. 즉 개별 데이터값의 분포도를 제공합니다.</p>
<p>value_counts() 메소드를 사용할 때는 Null 값을 무시하고 결과값을 내놓기 쉽습니다. value_counts()는 Null값을 포함하여 개별 데이터 값의 건수를 계산할지 여부를 dropna 인자로 판단합니다.</p>
<pre><code class="language-python">value_counts = titanic_df[&#39;Pclass&#39;].value_counts()
print(value_counts)
print(titanic_df[&#39;Embarked&#39;].value_counts(dropna=False)) # Null 값 포함한 분포도</code></pre>
<pre><code>3    491
1    216
2    184
Name: Pclass, dtype: int64
S      644
C      168
Q       77
NaN      2
Name: Embarked, dtype: int64</code></pre><pre><code class="language-python"># DataFrame에서도 value_counts() 적용 가능. 
titanic_df[[&#39;Pclass&#39;, &#39;Embarked&#39;]].value_counts()</code></pre>
<pre><code>Pclass  Embarked
3       S           353
2       S           164
1       S           127
        C            85
3       Q            72
        C            66
2       C            17
        Q             3
1       Q             2
dtype: int64</code></pre><h2 id="dataframe과-리스트-딕셔너리-넘파이-ndarray-상호-변환">DataFrame과 리스트, 딕셔너리, 넘파이 ndarray 상호 변환</h2>
<ul>
<li>넘파이 ndarray, 리스트, 딕셔너리를 DataFrame으로 변환하기</li>
</ul>
<pre><code class="language-python">import numpy as np

col_name1=[&#39;컬럼&#39;]
list1 = [1, 2, 3]
array1 = np.array(list1)

print(&#39;리스트로 만든 DataFrame \n&#39;, pd.DataFrame(list1, columns=col_name1))
print(&#39;ndarray로 만든 DataFrame \n&#39;, pd.DataFrame(array1, columns=col_name1))</code></pre>
<pre><code>리스트로 만든 DataFrame 
    컬럼
0   1
1   2
2   3
ndarray로 만든 DataFrame 
    컬럼
0   1
1   2
2   3</code></pre><pre><code class="language-python">col_name = [&#39;이름&#39;, &#39;나이&#39;, &#39;성별&#39;]
list1 = [
    [&#39;김경민&#39;, &#39;25&#39;, &#39;남&#39;],
    [&#39;김윤민&#39;, &#39;27&#39;, &#39;남&#39;],
    [&#39;이효리&#39;, &#39;22&#39;, &#39;여&#39;],
]
array1 = np.array(list1)
print(&#39;2차원 리스트로 만든 DataFrame \n&#39;, pd.DataFrame(list1, columns=col_name))
print(&#39;2차원 ndarray로 만든 DataFrame \n&#39;, pd.DataFrame(array1, columns=col_name))</code></pre>
<pre><code>2차원 리스트로 만든 DataFrame 
     이름  나이 성별
0  김경민  25  남
1  김윤민  27  남
2  이효리  22  여
2차원 리스트로 만든 DataFrame 
     이름  나이 성별
0  김경민  25  남
1  김윤민  27  남
2  이효리  22  여</code></pre><pre><code class="language-python">dic1 = {
    &#39;이름&#39; : [&#39;김경민&#39;, &#39;김윤민&#39;, &#39;이효리&#39;],
    &#39;나이&#39; : [25, 27, 22],
    &#39;성별&#39; : [&#39;남&#39;, &#39;남&#39;, &#39;여&#39;],
}
df_user = pd.DataFrame(dic1)
print(&#39;딕셔너리로 만든 DataFrame \n&#39;, df_user)</code></pre>
<pre><code>딕셔너리로 만든 DataFrame 
     이름  나이 성별
0  김경민  25  남
1  김윤민  27  남
2  이효리  22  여</code></pre><p>DataFrame을 ndarray, 리스트, 딕셔너리로 변환하기</p>
<pre><code class="language-python">col_name = [&#39;col1&#39;, &#39;col2&#39;, &#39;col3&#39;]
list1 = [
    [1,2,3],
    [2,3,4]
] 
df_list = pd.DataFrame(list1, columns = col_name)
print(&#39;DataFrame : \n&#39;,df_list)
print(&#39;DataFrame\&#39;s values \n&#39;, df_list.values, &#39;type?&#39;, type(df_list.values))
print(&#39;DataFrame to list \n&#39;,df_list.values.tolist(), &#39;type?&#39;, type(df_list.values.tolist()))</code></pre>
<pre><code>DataFrame : 
    col1  col2  col3
0     1     2     3
1     2     3     4
DataFrame&#39;s values 
 [[1 2 3]
 [2 3 4]] type? &lt;class &#39;numpy.ndarray&#39;&gt;
DataFrame to list 
 [[1, 2, 3], [2, 3, 4]] type? &lt;class &#39;list&#39;&gt;</code></pre><pre><code class="language-python">print(&#39;DataFrame to dict \n&#39;, df_list.to_dict(&#39;list&#39;), &#39;type?&#39;, type(df_list.to_dict()))</code></pre>
<pre><code>DataFrame to dict 
 {&#39;col1&#39;: [1, 2], &#39;col2&#39;: [2, 3], &#39;col3&#39;: [3, 4]} type? &lt;class &#39;dict&#39;&gt;</code></pre><h2 id="dataframe의-칼럼-데이터-세트-생성과-수정-삭제">DataFrame의 칼럼 데이터 세트 생성과 수정, 삭제</h2>
<pre><code class="language-python">df_user[&#39;address&#39;] = &#39;Seoul&#39;
df_user</code></pre>
<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

<pre><code>.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}</code></pre><p></style></p>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>이름</th>
      <th>나이</th>
      <th>성별</th>
      <th>address</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>김경민</td>
      <td>25</td>
      <td>남</td>
      <td>Seoul</td>
    </tr>
    <tr>
      <th>1</th>
      <td>김윤민</td>
      <td>27</td>
      <td>남</td>
      <td>Seoul</td>
    </tr>
    <tr>
      <th>2</th>
      <td>이효리</td>
      <td>22</td>
      <td>여</td>
      <td>Seoul</td>
    </tr>
  </tbody>
</table>
</div>




<pre><code class="language-python">df_user[&#39;10년후&#39;] = df_user[&#39;나이&#39;] + 10
df_user</code></pre>
<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

<pre><code>.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}</code></pre><p></style></p>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>이름</th>
      <th>나이</th>
      <th>성별</th>
      <th>address</th>
      <th>10년후</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>김경민</td>
      <td>25</td>
      <td>남</td>
      <td>Seoul</td>
      <td>35</td>
    </tr>
    <tr>
      <th>1</th>
      <td>김윤민</td>
      <td>27</td>
      <td>남</td>
      <td>Seoul</td>
      <td>37</td>
    </tr>
    <tr>
      <th>2</th>
      <td>이효리</td>
      <td>22</td>
      <td>여</td>
      <td>Seoul</td>
      <td>32</td>
    </tr>
  </tbody>
</table>
</div>




<pre><code class="language-python">df_user[&#39;나이/10후나이&#39;] = df_user[&#39;나이&#39;]/df_user[&#39;10년후&#39;]
df_user</code></pre>
<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

<pre><code>.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}</code></pre><p></style></p>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>이름</th>
      <th>나이</th>
      <th>성별</th>
      <th>address</th>
      <th>10년후</th>
      <th>나이/10후나이</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>김경민</td>
      <td>25</td>
      <td>남</td>
      <td>Seoul</td>
      <td>35</td>
      <td>0.714286</td>
    </tr>
    <tr>
      <th>1</th>
      <td>김윤민</td>
      <td>27</td>
      <td>남</td>
      <td>Seoul</td>
      <td>37</td>
      <td>0.729730</td>
    </tr>
    <tr>
      <th>2</th>
      <td>이효리</td>
      <td>22</td>
      <td>여</td>
      <td>Seoul</td>
      <td>32</td>
      <td>0.687500</td>
    </tr>
  </tbody>
</table>
</div>




<pre><code class="language-python">df_user = df_user.drop(&#39;address&#39;, axis=1) # 열을 지울 때는 label과 axis 1
df_user = df_user.drop(index = 0, axis=0) # 행을 지울 때는 index과 axis 0</code></pre>
<div>
<style scoped>
    .dataframe tbody tr th:only-of-type {
        vertical-align: middle;
    }

<pre><code>.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}</code></pre><p></style></p>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>이름</th>
      <th>나이</th>
      <th>성별</th>
      <th>10년후</th>
      <th>나이/10후나이</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1</th>
      <td>김윤민</td>
      <td>27</td>
      <td>남</td>
      <td>37</td>
      <td>0.729730</td>
    </tr>
    <tr>
      <th>2</th>
      <td>이효리</td>
      <td>22</td>
      <td>여</td>
      <td>32</td>
      <td>0.687500</td>
    </tr>
  </tbody>
</table>
</div>

<h2 id="index-객체">index 객체</h2>
<pre><code class="language-python">print(titanic_df.head().index)
col_name = [&#39;이름&#39;, &#39;나이&#39;, &#39;성별&#39;]
list1 = [
    [&#39;김경민&#39;, &#39;25&#39;, &#39;남&#39;],
    [&#39;김윤민&#39;, &#39;27&#39;, &#39;남&#39;],
    [&#39;이효리&#39;, &#39;22&#39;, &#39;여&#39;],
]
df_user=pd.DataFrame(list1,index=[&#39;1짱&#39;,&#39;2짱&#39;,&#39;3짱&#39;], columns=col_name)
print(df_user.index)</code></pre>
<pre><code>RangeIndex(start=0, stop=5, step=1)
Index([&#39;1짱&#39;, &#39;2짱&#39;, &#39;3짱&#39;], dtype=&#39;object&#39;)</code></pre><pre><code class="language-python">indexes = df_user.index
print(indexes,type(indexes.values))
print(indexes[0])</code></pre>
<pre><code>Index([&#39;1짱&#39;, &#39;2짱&#39;, &#39;3짱&#39;], dtype=&#39;object&#39;) &lt;class &#39;numpy.ndarray&#39;&gt;
1짱</code></pre><pre><code class="language-python">indexes[0] = &#39;5짱&#39; # 변경불가</code></pre>
<pre><code>Cell In [83], line 1
----&gt; 1 indexes[0] = &#39;5짱&#39;

TypeError: Index does not support mutable operations</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[카카오 REST API 소셜 로그인 feat. Django]]></title>
            <link>https://velog.io/@gaeng_man/%EC%B9%B4%EC%B9%B4%EC%98%A4-REST-API-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-feat.-Django</link>
            <guid>https://velog.io/@gaeng_man/%EC%B9%B4%EC%B9%B4%EC%98%A4-REST-API-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-feat.-Django</guid>
            <pubDate>Fri, 30 Dec 2022 18:21:12 GMT</pubDate>
            <description><![CDATA[<h1 id="rest-api-v2-카카오-소셜-로그인-가이드feat-django">REST API v2 카카오 소셜 로그인 가이드!(Feat. django)</h1>
<p>출처 : <a href="https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#before-you-begin-process">kakao developers doc</a></p>
<p><a href="https://velog.io/@devmin/kakao-login-basic">참고하면 괜찮을 블로그</a></p>
<h2 id="span-style-color--blue해야할-리스트사전-준비span"><span style= 'color : blue;'>해야할 리스트(사전 준비)</span></h2>
<h3 id="1-카카오-developers에서-애플리케이션-추가하기">1. 카카오 developers에서 애플리케이션 추가하기</h3>
<p><img src="https://velog.velcdn.com/images/gaeng_man/post/a1de62f4-192a-4dec-a1b1-238e8fa38aec/image.png" alt=""></p>
<h3 id="2-추가한-애플리케이션에-들어가서-앱키-받아놓기앱키는-노출되지-않게-주의해-주세요">2. 추가한 애플리케이션에 들어가서 앱키 받아놓기(앱키는 노출되지 않게 주의해 주세요!)</h3>
<p><img src="https://velog.velcdn.com/images/gaeng_man/post/da8f0f1d-96e8-421b-8571-f129d4bce440/image.png" alt=""></p>
<h3 id="3-앱-설정의-플랫폼에-들어가-web-url에-내-사이트-등록하기">3. 앱 설정의 플랫폼에 들어가 Web URL에 내 사이트 등록하기</h3>
<p><img src="https://velog.velcdn.com/images/gaeng_man/post/391bf93c-67e0-4742-bf7d-b7f96088f40b/image.png" alt=""></p>
<h3 id="4-필요한-정보를-동의항목에서-설정하기">4. 필요한 정보를 동의항목에서 설정하기</h3>
<p><img src="https://velog.velcdn.com/images/gaeng_man/post/a43f8786-c832-4f19-9729-3c0cf316d1d3/image.png" alt=""></p>
<h3 id="5-카카오-로그인-활성화와-redirect-uri-설정하기">5. 카카오 로그인 활성화와 redirect URI 설정하기</h3>
<p><b style="font-size: 1.1em">5-1) 백 엔드에서 redierct uri를 받을 url설정하기
    - 처리를 원하는 url을 설정해 줍니다.</b></p>
<pre><code class="language-python"># urls.py
from django.urls import path
from user.views import kakao_social_login, kakao_social_login_callback

urlpatterns = [
    #로그인 요청을 보낼 url
    path(&#39;account/login/kakao/&#39;, kakao_social_login, name=&#39;kakao_login&#39;),
    #받은 인가 코드로 접근 토근을 받아 유저의 정보를 가져올 url
    path(&#39;account/login/kakao/callback/&#39;, kakao_social_login_callback, name=&#39;kakao_login_callback&#39;),
]


# views.py
def kakao_social_login(request):
    pass

def kakao_social_login_callback(request):
    pass
</code></pre>
<p><b style="font-size: 1.1em">5-2) 프론트 엔드에서 버튼을 만들기!</b></p>
<pre><code class="language-html">&lt;!--  로그인 버튼과 백엔드에서 설정해준 URL로 설정하기    --&gt;
&lt;a id=&quot;kakao-login-btn&quot; href=&quot;/account/login/kakao&quot;&gt;
    &lt;img src=&quot;https://k.kakaocdn.net/14/dn/btroDszwNrM/I6efHub1SN5KCJqLm1Ovx1/o.jpg&quot; width=&quot;222&quot; alt=&quot;카카오 로그인 버튼&quot;/&gt;
&lt;/a&gt;</code></pre>
<p><b style="font-size: 1.1em">5-3) 카카오 developers에서 로그인 활성화 &amp; redirect uri 등록하기</b>
<img src="https://velog.velcdn.com/images/gaeng_man/post/cd86d07e-2120-4076-a22b-0153aeb8e203/image.png" alt=""></p>
<h2 id="span-style-color--bluerest-api로-인증-요청-및-접근-코드-받아서-사용자-정보-활용하기span"><span style= 'color : blue;'>REST API로 인증 요청 및 접근 코드 받아서 사용자 정보 활용하기</span></h2>
<p><img src="https://velog.velcdn.com/images/gaeng_man/post/6d6d0739-b449-4b5e-96cf-b10d88428583/image.png" alt=""></p>
<p><b style="font-size: 1.1em">저희가 처리해야할 부분은 4개가 되겠습니다.</b></p>
<h3 id="1번---oauthauthorize-에-요청-보내기">1번 - /oauth/authorize 에 요청 보내기</h3>
<pre><code class="language-python">def kakao_social_login(request):
    &quot;&quot;&quot;
    카카오톧에 나의 애플리케이션의 정보를 담아 사용자에게 카카오 로그인 요청
    &quot;&quot;&quot;
    if request.method == &#39;GET&#39;:
        client_id = CLIENT_ID # 앱키 ex) b923j1i23k4io1l2k3ji1uaq2
        redirect_uri = &#39;http://127.0.0.1:8000/account/login/kakao/callback&#39; # 인가 코드를 받을 uri
        return redirect(
            f&#39;https://kauth.kakao.com/oauth/authorize?client_id={client_id}&amp;redirect_uri={redirect_uri}&amp;response_type=code&#39;
        )</code></pre>
<h3 id="2번-redirect-uri로-전달된-인가-코드를-받기">2번 Redirect URI로 전달된 인가 코드를 받기</h3>
<p><code>pip install requests</code></p>
<pre><code class="language-python">def kakao_social_login_callback(request):
    &quot;&quot;&quot;
    받은 인가 코드, 애플리케이션 정보를 담아 /oath/token/에 post요청하여 접근코드를 받아 처리하는 함수
    &quot;&quot;&quot;
    try:
        code = request.GET.get(&#39;code&#39;)
#         client_id = CLIENT_ID
#         redirect_uri = &#39;http://127.0.0.1:8000/account/login/kakao/callback&#39; # 인가 코드를 받은 URI
#         token_request = requests.post(
#             &#39;https://kauth.kakao.com/oauth/token&#39;, {&#39;grant_type&#39;: &#39;authorization_code&#39;,
#                                                     &#39;client_id&#39;: client_id, &#39;redierect_uri&#39;: redirect_uri, &#39;code&#39;: code}
#         )

#         token_json = token_request.json()

#         error = token_json.get(&#39;error&#39;, None)

#         if error is not None:
#             print(error)
#             return JsonResponse({&quot;message&quot;: &quot;INVALID_CODE&quot;}, status=400)

#         access_token = token_json.get(&quot;access_token&quot;)

#     except KeyError:
#         return JsonResponse({&quot;message&quot;: &quot;INVALID_TOKEN&quot;}, status=400)

#     except access_token.DoesNotExist:
#         return JsonResponse({&quot;message&quot;: &quot;INVALID_TOKEN&quot;}, status=400)

#         #------get kakaotalk profile info------#

#     profile_request = requests.get(
#         &quot;https://kapi.kakao.com/v2/user/me&quot;, headers={&quot;Authorization&quot;: f&quot;Bearer {access_token}&quot;},
#     )
#     profile_json = profile_request.json()
#     kakao_id = profile_json.get(&#39;id&#39;)
#     username = profile_json[&#39;properties&#39;][&#39;nickname&#39;]</code></pre>
<h3 id="3번-oauthtoken에-인가-코드를-담아-접근-토큰-받기">3번 /oauth/token에 인가 코드를 담아 접근 토큰 받기</h3>
<pre><code class="language-python">def kakao_social_login_callback(request):
    &quot;&quot;&quot;
    받은 인가 코드, 애플리케이션 정보를 담아 /oath/token/에 post요청하여 접근코드를 받아 처리하는 함수
    &quot;&quot;&quot;
    try:
        code = request.GET.get(&#39;code&#39;)
        client_id = CLIENT_ID # 앱 키
        redirect_uri = &#39;http://127.0.0.1:8000/account/login/kakao/callback&#39; # 인가 코드를 받은 URI, 이 부분은 크게 상관이 없어보입니다.
        token_request = requests.post(
            # grant_type은 authorization_code로 고정입니다.
            &#39;https://kauth.kakao.com/oauth/token&#39;, {&#39;grant_type&#39;: &#39;authorization_code&#39;,
                                                    &#39;client_id&#39;: client_id, &#39;redierect_uri&#39;: redirect_uri, &#39;code&#39;: code}
        )

        token_json = token_request.json()

#         error = token_json.get(&#39;error&#39;, None)

#         if error is not None:
#             print(error)
#             return JsonResponse({&quot;message&quot;: &quot;INVALID_CODE&quot;}, status=400)

#         access_token = token_json.get(&quot;access_token&quot;)

#     except KeyError:
#         return JsonResponse({&quot;message&quot;: &quot;INVALID_TOKEN&quot;}, status=400)

#     except access_token.DoesNotExist:
#         return JsonResponse({&quot;message&quot;: &quot;INVALID_TOKEN&quot;}, status=400)

#         #------get kakaotalk profile info------#

#     profile_request = requests.get(
#         &quot;https://kapi.kakao.com/v2/user/me&quot;, headers={&quot;Authorization&quot;: f&quot;Bearer {access_token}&quot;},
#     )
#     profile_json = profile_request.json()
#     kakao_id = profile_json.get(&#39;id&#39;)
#     username = profile_json[&#39;properties&#39;][&#39;nickname&#39;]</code></pre>
<h3 id="4번-토큰-유효성-검증-후-토큰으로-사용자의-정보-조회와-서비스-내에서-처리">4번 토큰 유효성 검증 후 토큰으로 사용자의 정보 조회와 서비스 내에서 처리</h3>
<pre><code class="language-python">def kakao_social_login_callback(request):
    &quot;&quot;&quot;
    받은 인가 코드, 애플리케이션 정보를 담아 /oath/token/에 post요청하여 접근코드를 받아 처리하는 함수
    &quot;&quot;&quot;
    try:
        code = request.GET.get(&#39;code&#39;)
        client_id = CLIENT_ID # 앱 키
        redirect_uri = &#39;http://127.0.0.1:8000/account/login/kakao/callback&#39; # 인가 코드를 받은 URI
        token_request = requests.post(
            &#39;https://kauth.kakao.com/oauth/token&#39;, {&#39;grant_type&#39;: &#39;authorization_code&#39;,
                                                    &#39;client_id&#39;: client_id, &#39;redierect_uri&#39;: redirect_uri, &#39;code&#39;: code}
        )

        token_json = token_request.json()
        #------------유효성 검증 --------------#
        error = token_json.get(&#39;error&#39;, None)

        if error is not None:
            print(error)
            return JsonResponse({&quot;message&quot;: &quot;INVALID_CODE&quot;}, status=400)
        #-------------받은 토큰---------------#
        access_token = token_json.get(&quot;access_token&quot;)

    except KeyError:
        return JsonResponse({&quot;message&quot;: &quot;INVALID_TOKEN&quot;}, status=400)

    except access_token.DoesNotExist:
        return JsonResponse({&quot;message&quot;: &quot;INVALID_TOKEN&quot;}, status=400)

    #------토큰을 이용하여 사용자 정보 조회------#
    profile_request = requests.get(
        &quot;https://kapi.kakao.com/v2/user/me&quot;, headers={&quot;Authorization&quot;: f&quot;Bearer {access_token}&quot;},
    )
    #------사용자 정보를 활용---------------#
    profile_json = profile_request.json()
    print(profile_json)
    kakao_id = profile_json.get(&#39;id&#39;)
    username = profile_json[&#39;properties&#39;][&#39;nickname&#39;]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[numpy 기초! (reshape(), 인덱싱, sort(), argsort(), dot(), transpose())]]></title>
            <link>https://velog.io/@gaeng_man/numpy-%EA%B8%B0%EC%B4%88-reshape-%EC%9D%B8%EB%8D%B1%EC%8B%B1-sort-argsort-dot-transpose</link>
            <guid>https://velog.io/@gaeng_man/numpy-%EA%B8%B0%EC%B4%88-reshape-%EC%9D%B8%EB%8D%B1%EC%8B%B1-sort-argsort-dot-transpose</guid>
            <pubDate>Fri, 30 Dec 2022 18:16:34 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-python">import numpy as np</code></pre>
<h1 id="pythonnumpy--기초_attr_2-reshape-인덱싱-sort-argsort-dot-transpose">[Python/numpy]  기초_attr_2 (reshape(), 인덱싱, sort(), argsort(), dot(), transpose())</h1>
<h2 id="reshape">reshape()</h2>
<ul>
<li>ndarray의 차원과 크기를 변경하는 method</li>
</ul>
<pre><code class="language-python">array1 = np.arange(8)
print(array1)
array2 = array1.reshape(2,4)
print(array2)
array3 = array2.reshape(2,2,2)
print(array3)</code></pre>
<pre><code>[0 1 2 3 4 5 6 7]
[[0 1 2 3]
 [4 5 6 7]]

[[[0 1]
  [2 3]]

 [[4 5]
  [6 7]]]</code></pre><p><span style='font-size : 16px'>알 수 없는(계산하기 귀찮은) 차원의 자리에 -1을 넣는다면 알아서 계산해 준다.</span></p>
<pre><code class="language-python">array2 = array1.reshape(-1, 2)
print(array2) # (4,2) 2차원 4행 2열</code></pre>
<pre><code>[[0 1]
 [2 3]
 [4 5]
 [6 7]]</code></pre><p>만약 둘 이상의 인자에 -1을 넣는다면?
<code>ValueError : can only specify one unknown dimension</code>
알 수 없는 차원(-1)을 하나만 지정할 수 있습니다.</p>
<h2 id="인덱싱---데이터-세트-선택하기">인덱싱 - 데이터 세트 선택하기</h2>
<table>
<thead>
<tr>
<th align="center">인덱싱 유형</th>
<th align="left">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="center">특정 위치의 단일 값 추출</td>
<td align="left">원하는 위치의 인덱스 값을 지정</td>
</tr>
<tr>
<td align="center">슬라이싱</td>
<td align="left">[시작인덱스:끝 인덱스]</td>
</tr>
<tr>
<td align="center">팬시 인덱싱(Fancy Indexing)</td>
<td align="left">일정한 인덱싱 집합을 리스트 또는 ndarray 형태로 지정해 해당 위치에 있는 ndarray를 반환한다.</td>
</tr>
<tr>
<td align="center">불린 인덱싱(Boolean Indexing)</td>
<td align="left">특정 조건에 해당 여부로 ndarray를 반환한다.</td>
</tr>
</tbody></table>
<h3 id="1-단일-인덱싱">1. 단일 인덱싱</h3>
<pre><code class="language-python">array1 = np.arange(1,11)
print(&#39;#-----1차원-----#&#39;)
print(array1)
print(&#39;1번 인덱스 데이터 &gt;&gt;&gt;&#39;,array1[1])
print(&#39;[-1]마지막 데이터 &gt;&gt;&gt;&#39;,array1[-1])
print(&#39;#-----2차원-----#&#39;)
array2 = array1.reshape(-1,5)
print(array2)
print(&#39;[1,4] 2행 5열의 데이터 &gt;&gt;&gt;&#39;,array2[1,4])</code></pre>
<pre><code>#-----1차원-----#
[ 1  2  3  4  5  6  7  8  9 10]
1번 인덱스 데이터 &gt;&gt;&gt; 2
마지막 데이터 &gt;&gt;&gt; 10

#-----2차원-----#
[[ 1  2  3  4  5]
 [ 6  7  8  9 10]]
2행 5열의 데이터 &gt;&gt;&gt; 10</code></pre><h3 id="2-슬라이싱">2. 슬라이싱</h3>
<pre><code class="language-python">array1 = np.arange(1,11)
print(&#39;#-----1차원-----#&#39;)
print(array1[:5])
print(array1[:5:-1])
print(array1[10:5:-1])
print(array1[::2])
print(&#39;#-----2차원-----#&#39;)
array2 = array2.reshape(5,-1)
print(array2)
print(&#39;2차원nd배열[0:1,2:4] \n&#39;, array2[0:1, 2:4])
print(&#39;2차원nd배열[2:4,0:1] \n&#39;, array2[2:4, 0:1])
print(&#39;2차원nd배열[:4,:] \n&#39;, array2[:4, :])
print(&#39;#-----2차원에서 단일 인덱싱 실행 시 차원의 변화-----#&#39;)
print(&#39;2차원nd배열[0], 2차원nd배열[0].shape \n&#39;, array2[0], &#39;차원은?&#39;, array2[0].shape)</code></pre>
<pre><code>#-----1차원-----#
[1 2 3 4 5]
[10  9  8  7]
[10  9  8  7]
[1 3 5 7 9]

#-----2차원-----#
[[ 1  2]
 [ 3  4]
 [ 5  6]
 [ 7  8]
 [ 9 10]]
2차원nd배열[0:1,2:4] 
 []
2차원nd배열[2:4,0:1] 
 [[5]
 [7]]
2차원nd배열[:4,:] 
 [[1 2]
 [3 4]
 [5 6]
 [7 8]]

#-----2차원에서 단일 인덱싱 실행 시 차원의 변화-----#

2차원nd배열[0], 2차원nd배열[0].shape 
 [1 2] 차원은? (2,)</code></pre><h3 id="3-팬시-인덱싱">3. 팬시 인덱싱!</h3>
<ul>
<li>일정한 인덱싱 집합을 리스트 또는 ndarray 형태로 지정해 해당 위치에 있는 ndarray를 반환한다.</li>
</ul>
<pre><code class="language-python">array1 = np.arange(1,11)
array2 = array1.reshape(2,5)
print(array2)
print(&#39;2차원nd배열[1, 2:3] \n&#39;, array2[[1], 2:3])
print(&#39;2차원nd배열[:, [0,2,4]] \n&#39;, array2[:, [0,2,4]])
print(&#39;2차원nd배열[:, [0,2,4]].tolist() 리스트로 변환해보기 \n&#39;, array2[:, [0,2,4]].tolist())</code></pre>
<pre><code>[[ 1  2  3  4  5]
 [ 6  7  8  9 10]]
2차원nd배열[1, 2:3] 
 [[8]]

2차원nd배열[:, [0,2,4]] 
 [[ 1  3  5]
 [ 6  8 10]]

2차원nd배열[:, [0,2,4]].tolist() 리스트로 변환해보기 
 [[1, 3, 5], [6, 8, 10]]</code></pre><h3 id="4-불린-인덱싱">4. 불린 인덱싱!!</h3>
<ul>
<li>특정 조건에 해당 여부로 ndarray를 반환한다.</li>
</ul>
<pre><code class="language-python">array1 = np.arange(1,11)

print(&#39;#-----1차원-----#&#39;)
짝수판별_nd배열 = array1 % 2 == 0
print(&#39;짝수판별 1차원 ndarray \n&#39;,짝수판별_nd배열)
print(&#39;타입은?&#39;, type(짝수판별_nd배열), &#39;차원은?&#39;, 짝수판별_nd배열.shape)

print(&#39;#-----1차원에 불린 인덱싱 정룔 후 변화-----#&#39;)
print(array1[짝수판별_nd배열])
print(&#39;차원은?&#39;, array1[짝수판별_nd배열].shape)

print(&#39;#-----2차원-----#&#39;)
array2 = array1.reshape(-1,5)
짝수판별_2차원_nd배열 = array2 % 2 == 0
print(&#39;짝수판별 2차원 ndarray \n&#39;,짝수판별_2차원_nd배열)
print(&#39;타입은?&#39;, type(짝수판별_2차원_nd배열), &#39;차원은?&#39;, 짝수판별_2차원_nd배열.shape)

print(&#39;#-----2차원에 불린 인덱싱 적용 후 변화-----#&#39;)
print(array2[짝수판별_2차원_nd배열])
print(&#39;차원은?&#39;, array2[짝수판별_2차원_nd배열].shape)</code></pre>
<pre><code>#-----1차원-----#
짝수판별 1차원 ndarray 
 [False  True False  True False  True False  True False  True]

타입은? &lt;class &#39;numpy.ndarray&#39;&gt; 차원은? (10,)

#-----1차원에 불린 인덱싱 정룔 후 변화-----#
[ 2  4  6  8 10]

차원은? (5,)

#-----2차원-----#
짝수판별 2차원 ndarray 
 [[False  True False  True False]
 [ True False  True False  True]]

타입은? &lt;class &#39;numpy.ndarray&#39;&gt; 차원은? (2, 5)

#-----2차원에 불린 인덱싱 적용 후 변화-----#
[ 2  4  6  8 10]

차원은? (5,)</code></pre><h3 id="불린-인덱싱-사용법을-파이썬으로-이해하기">불린 인덱싱 사용법을 파이썬으로 이해하기</h3>
<pre><code class="language-python">print(array1[array1%2 == 0])</code></pre>
<pre><code>[ 2  4  6  8 10]</code></pre><p>파이썬 문법으로 바꿔보기</p>
<pre><code class="language-python">print(list(x for x in array1 if x%2 == 0))</code></pre>
<pre><code>[2, 4, 6, 8, 10]</code></pre><h2 id="sort">sort()</h2>
<ul>
<li>np.sort()      : 원본 배열을 참조하여 새로 정렬된 배열을 반환한다. (Like 파이썬의 sorted() )</li>
<li>ndarray.sort() : 원본 배열 자체를 정렬한다. 반환 값은 None     (Like 파이썬의 .sort() )</li>
</ul>
<pre><code class="language-python">원본배열 = np.array([3,1,5,7,4,9])
np.sort사용배열 = np.sort(원본배열)
print(&#39;np.sort사용배열&#39;, np.sort사용배열, &#39;원본배열&#39;, 원본배열)
원본배열.sort()
print(&#39;원본배열.sort()실행 후 원본 배열&#39;, 원본배열)</code></pre>
<pre><code>np.sort사용배열 [1 3 4 5 7 9] 원본배열 [3 1 5 7 4 9]
원본배열.sort()실행 후 원본 배열 [1 3 4 5 7 9]</code></pre><pre><code class="language-python">원본배열 = np.array([[2,1],[0,3],[9,6],[6,2]])
디폴트이차원정렬배열 = np.sort(원본배열) # 디폴트로 axis = -1 열을 기준으로 정렬해 준다.
행기준이차원정렬배열 = np.sort(원본배열, axis = 0)
print(&#39;원본배열\n&#39;, 원본배열)
print(&#39;기본이차원정렬배열\n&#39;, 디폴트이차원정렬배열)
print(&#39;행기준이차원정렬배열 \n&#39;, 행기준이차원정렬배열)</code></pre>
<pre><code>원본배열
 [[2 1]
 [0 3]
 [9 6]
 [6 2]]
기본이차원정렬배열
 [[1 2]
 [0 3]
 [6 9]
 [2 6]]
행기준이차원정렬배열 
 [[0 1]
 [2 2]
 [6 3]
 [9 6]]</code></pre><h2 id="argsort">argsort()</h2>
<ul>
<li>정렬된 행렬의 인덱스를 반환하는 메서드</li>
</ul>
<pre><code class="language-python">array1 = np.array([100,10,1000,10000])
array1_argsort = np.argsort(array1)
print(&#39;오름 차순으로 정렬하려면 어떻게 기존 배열에서 어떤 인덱스가 차례로 들어와야 하나요??&#39;, array1_argsort)
print(array1[1], array1[0], array1[2], array1[3])</code></pre>
<pre><code>오름 차순으로 정렬하려면 어떻게 기존 배열에서 어떤 인덱스가 차례로 들어와야 하나요?? [1 0 2 3]
10 100 1000 10000</code></pre><p>이건 언제 필요하나요?</p>
<pre><code class="language-python">name_list = np.array([&#39;kim&#39;, &#39;lee&#39;, &#39;park&#39;, &#39;han&#39;])# 우리 팀원들 5명의 리스트
score_list = np.array([25, 99, 12, 39])# 우리 팀원들의 점수 리스트</code></pre>
<p>상황) 우리 팀원들을 점수 순(오름차순과 내림차순)으로 나열해 주세요!</p>
<pre><code class="language-python">score_argsort = np.argsort(score_list)
print(score_argsort)
print(&#39;오름차순&#39;,name_list[score_argsort])
print(&#39;내림차순&#39;,name_list[score_argsort][::-1])</code></pre>
<pre><code>[2 0 3 1]
오름차순 [&#39;park&#39; &#39;kim&#39; &#39;han&#39; &#39;lee&#39;]
내림차순 [&#39;lee&#39; &#39;han&#39; &#39;kim&#39; &#39;park&#39;]</code></pre><h2 id="선형대수-연산---행렬-내적곱셈과-전치-행렬-구하기">선형대수 연산 - 행렬 내적(곱셈)과 전치 행렬 구하기!</h2>
<h3 id="행렬-내적">행렬 내적</h3>
<p><a href="https://www.youtube.com/watch?v=JpSe38UHaos">행렬의 내적 구하기 유튜브(강추)</a></p>
<pre><code class="language-python">A = np.array([[1, 2, 3],
              [4, 5, 6]])
B = np.array([[7, 8],
              [9, 10],
              [11, 12]])

내적 = np.dot(A, B)
print(&#39;행렬 내적 결과 :\n&#39;, 내적)</code></pre>
<pre><code>행렬 내적 결과 :
 [[ 58  64]
 [139 154]]</code></pre><h3 id="transpose-전치-행렬">transpose() 전치 행렬</h3>
<pre><code class="language-python">print(np.transpose(A))</code></pre>
<pre><code>[[1 4]
 [2 5]
 [3 6]]</code></pre>]]></description>
        </item>
    </channel>
</rss>