<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>god_glory</title>
        <link>https://velog.io/</link>
        <description>오직 실력만이 나를 증명한다.</description>
        <lastBuildDate>Thu, 24 Apr 2025 14:24:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>god_glory</title>
            <url>https://velog.velcdn.com/images/glory_joo/profile/5c794878-f0ec-4def-8711-515f27ad292f/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. god_glory. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/glory_joo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[middleware와 Django]]></title>
            <link>https://velog.io/@glory_joo/middleware%EC%99%80-Django</link>
            <guid>https://velog.io/@glory_joo/middleware%EC%99%80-Django</guid>
            <pubDate>Thu, 24 Apr 2025 14:24:02 GMT</pubDate>
            <description><![CDATA[<p>Django에는 middleware라는 개념이있다. 이건 fastapi에도 있고</p>
<p>다른 프레임워크에도 다른 이름으로 같은 기능을 하는 것들이 많다. </p>
<p>프레임워크 | 이름 | 역할
Django | Middleware | 인증, CSRF, 세션 처리 등
Express (Node.js) | Middleware (app.use()) | 요청 로그, CORS 처리 등
Spring (Java) | Filter / Interceptor | 인증, 권한 검사, 로깅
Laravel (PHP) | Middleware | 사용자 인증, 라우팅 제한
FastAPI | Middleware | CORS, 로그, 에러 처리 등
Ruby on Rails | Rack Middleware | 요청 전후 처리</p>
<p>장고에서 실제 쓰는 미들웨어를 보면</p>
<p>MIDDLEWARE = [
    &#39;corsheaders.middleware.CorsMiddleware&#39;,
    &#39;django.middleware.security.SecurityMiddleware&#39;,
    &#39;django.contrib.sessions.middleware.SessionMiddleware&#39;,
    &#39;django.middleware.common.CommonMiddleware&#39;,
    &#39;django.middleware.csrf.CsrfViewMiddleware&#39;, 
    &#39;django.contrib.auth.middleware.AuthenticationMiddleware&#39;,
    &#39;django.contrib.messages.middleware.MessageMiddleware&#39;,
    &#39;django.middleware.clickjacking.XFrameOptionsMiddleware&#39;,
    &#39;allauth.account.middleware.AccountMiddleware&#39;,
]</p>
<p>cors, https, session기반 로그인/로그아웃, csrf, clickjacking 방지 등등</p>
<p>생각보다 많은 기능을 한다. </p>
<p>간단히 표현하면 클라이언트와 view 사이에서 요청을 잠시 hook하여 요청에 다양한 효과를 부과한다음 전달하는 기능이라고 이해하면 될듯하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[python 메모리누수와 ducktyping]]></title>
            <link>https://velog.io/@glory_joo/python-%EB%A9%94%EB%AA%A8%EB%A6%AC%EB%88%84%EC%88%98%EC%99%80-ducktyping</link>
            <guid>https://velog.io/@glory_joo/python-%EB%A9%94%EB%AA%A8%EB%A6%AC%EB%88%84%EC%88%98%EC%99%80-ducktyping</guid>
            <pubDate>Thu, 24 Apr 2025 13:58:45 GMT</pubDate>
            <description><![CDATA[<p>파이썬은 메모리누수가 없는 언어이다. </p>
<p>레퍼런스 카운팅이라고 하는데 객체를 참조하면 1이 증가하고, 참조가 없어지면 다시 0이되는 방식으로 메모리를 처리하고 </p>
<p>세대별 가비지컬렉션으로 순환참조도 처리하여 메모리 누수를 막는다. </p>
<p>duck typing은 </p>
<p>오리처럼 울고, 오리처럼 걸으면 오리다. </p>
<p>이런 옛말이라고 하는데 파이썬에서 타입이 정해지지 않아도 그 타입처럼 작동한다면 그 타입으로 본다는것이다. </p>
<p>파이썬은 동적언어라서 코드의 타입을 정하지 않아도, 동작만으로 타입을 판단할 수 있고 그래서 깔끔한 코드 구현이 가능하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[python의 pandas, numpy]]></title>
            <link>https://velog.io/@glory_joo/python%EC%9D%98-pandas-numpy</link>
            <guid>https://velog.io/@glory_joo/python%EC%9D%98-pandas-numpy</guid>
            <pubDate>Thu, 24 Apr 2025 13:55:39 GMT</pubDate>
            <description><![CDATA[<p>왜 pandas, numpy는 고성능 수치 연산인가</p>
<p>이 둘은 c언어를 기반으로 돌아가는 라이브러리기 때문이다. </p>
<p>이건 컴파일언어와 인터프리터 언어의 차이를 알고 가야한다. </p>
<p>python은 인터프리터 언어로 한줄한줄 해석하며, 타입, 객체 등을 정하며 해석하기 때문에 느리지만</p>
<p>c언어는 컴파일언어로 적으면 바로 기계어 바이너리 기계식 언어로 해석한걸 읽기 때문에 </p>
<p>10~100배정도 차이가 난다. </p>
<p>java는 컴파일, 인터프리터 언어가 복합되어 구성되어있다. </p>
<p>그래서 두개의 라이브러리는 c언어 기반으로 계산을 하기때문에 계산 속도가 파이썬과 비교가 안된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflow_project 35]]></title>
            <link>https://velog.io/@glory_joo/livflowproject-35</link>
            <guid>https://velog.io/@glory_joo/livflowproject-35</guid>
            <pubDate>Fri, 21 Mar 2025 10:14:31 GMT</pubDate>
            <description><![CDATA[<p>test_user 만든거 적기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflowproject 33]]></title>
            <link>https://velog.io/@glory_joo/livflowproject-33</link>
            <guid>https://velog.io/@glory_joo/livflowproject-33</guid>
            <pubDate>Fri, 21 Mar 2025 10:12:48 GMT</pubDate>
            <description><![CDATA[<p>postman 활용한 내용 적기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflow project]]></title>
            <link>https://velog.io/@glory_joo/livflow-project</link>
            <guid>https://velog.io/@glory_joo/livflow-project</guid>
            <pubDate>Fri, 21 Mar 2025 10:12:29 GMT</pubDate>
            <description><![CDATA[<p>recipe_img 적기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflow_project 31]]></title>
            <link>https://velog.io/@glory_joo/livflowproject-31</link>
            <guid>https://velog.io/@glory_joo/livflowproject-31</guid>
            <pubDate>Fri, 21 Mar 2025 10:12:10 GMT</pubDate>
            <description><![CDATA[<p>2중 로직 차감 적기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflow project 30]]></title>
            <link>https://velog.io/@glory_joo/livflow-project-30</link>
            <guid>https://velog.io/@glory_joo/livflow-project-30</guid>
            <pubDate>Fri, 21 Mar 2025 10:11:46 GMT</pubDate>
            <description><![CDATA[<p>original_stock 개념적기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflow project 28 - SOCIAL LOGIN 백엔드 정리편]]></title>
            <link>https://velog.io/@glory_joo/livflow-project-28-SOCIAL-LOGIN-%EB%B0%B1%EC%97%94%EB%93%9C-%EC%A0%95%EB%A6%AC%ED%8E%B8</link>
            <guid>https://velog.io/@glory_joo/livflow-project-28-SOCIAL-LOGIN-%EB%B0%B1%EC%97%94%EB%93%9C-%EC%A0%95%EB%A6%AC%ED%8E%B8</guid>
            <pubDate>Wed, 05 Feb 2025 17:59:14 GMT</pubDate>
            <description><![CDATA[<p>소셜로그인에 다양한 방법이 있지만 프론트, 백엔드 통합 부분으로 정리를 해보고자한다. </p>
<p>나중에 소셜로그인을 하게된다면 이 정리를 보고 다시 할 수 있을 정도로 정리해보자. </p>
<p>우선 구글로그인 하나만 해도 나머진 할 수 있으니까 구글로만 정리를 해보려고한다. </p>
<p>우선 구글 개발자 콘솔에 들어가야한다. </p>
<p><a href="https://console.cloud.google.com/">https://console.cloud.google.com/</a></p>
<p>API 만드는데 들어가서 &quot;OAuth 동의 화면&quot;를 들어간다. </p>
<p>그 뒤 웹페이지 클라이언트를 만들어서 안에 들어가보면 다음과 같이 있을거다.</p>
<p>승인된 JavaScript 원본
승인된 리디렉션 URI</p>
<p>승인된 JavaScript 원본
여기에는 내가 사용하는 프로젝트의 주소, 아니면 테스트할 로컬 주소를 입력하면된다. 
나의 경우는 <a href="https://www.livflow.co.kr">https://www.livflow.co.kr</a>, <a href="http://localhost:5173">http://localhost:5173</a>
이렇게 2개를 입력해주면 된다. </p>
<p>승인된 리디렉션 URI
로그인 이후에 올 페이지 엔드포인트를 적어주면된다. 
<a href="http://localhost:5173/auth/login/callback/google">http://localhost:5173/auth/login/callback/google</a>
이런식으로 해두었다. </p>
<p>이제 소셜로그인의 플로우를 봐보자</p>
<p>[사용자] → (로그인 버튼 클릭)
       ↓
[프론트엔드] → (구글 인증 서버로 리디렉션)
       ↓
[구글 로그인 완료] → (인가 코드 발급)
       ↓
[프론트엔드] → (인가 코드 백엔드로 전송)
       ↓
[백엔드] → (인가 코드로 액세스 토큰 요청)
       ↓
[구글] → (액세스 토큰 + 사용자 정보 반환)
       ↓
[백엔드] → (JWT 발급 + Redis에 리프레시 토큰 저장)
       ↓
[프론트엔드] ← (액세스 토큰 쿠키로 전달)
       ↓
[사용자 로그인 완료 🚀]</p>
<p>구글 인증서버는 이런 주소를 쓴다. 
 <a href="https://accounts.google.com/o/oauth2/v2/auth">https://accounts.google.com/o/oauth2/v2/auth</a>
그럼 여기로 가서 사용자가 구글로그인을 성공하면 인가코드가 나온다. 
그럼 인가코드를 백엔드로 전송해서 해당 함수에 넣어야한다 .</p>
<pre><code>class GoogleAuth(APIView):
    authentication_classes = []
    permission_classes = [AllowAny]

    def post(self, request, *args, **kwargs):
        code = request.data.get(&quot;code&quot;)
        token_endpoint = &quot;https://oauth2.googleapis.com/token&quot;
        data = {
            &quot;code&quot;: code,
            &quot;client_id&quot;: os.getenv(&quot;GOOGLE_CLIENT_ID&quot;),
            &quot;client_secret&quot;: os.getenv(&quot;GOOGLE_CLIENT_SECRET&quot;),
            &quot;redirect_uri&quot;: os.getenv(&quot;GOOGLE_REDIRECT_URI&quot;),
            &quot;grant_type&quot;: &quot;authorization_code&quot;,
        }</code></pre><p>  만약 이 엔드포인트가 
  <a href="http://www.api.liv/google/login/callback/">www.api.liv/google/login/callback/</a>
  이런식이라고 보면 </p>
<p>  프론트 엔드에서는 이 엔드포인트로 인가코드를 전달해야한다. </p>
<p>  그럼 Googleauth라는 함수에서 </p>
<pre><code>  &quot;code&quot;: code,</code></pre><p>  이 부분에서 인가코드를 받고 구글 개발자 콘솔에 있는 client_id, client_secret, redirect_uri 이 부분을 <a href="https://oauth2.googleapis.com/token">https://oauth2.googleapis.com/token</a> 이 주소로 보내게 된다. </p>
<p>  그럼 코드와 id, secret, uri가 모두 일치한다면 </p>
<p>  구글에서는 액세스 토큰과 리프레시 토큰을 재발급해준다. </p>
<p>  그럼 이 토큰을 가지고</p>
<p>  <a href="https://www.googleapis.com/oauth2/v2/userinfo">https://www.googleapis.com/oauth2/v2/userinfo</a></p>
<p>이 엔드포인트에 보내 원하는 유저 정보를 받아온다. </p>
<p>그 뒤 해당 정보를 가지고 백엔드 jwt에서 자체적으로 토큰을 제작한다 .</p>
<p>이 이름도 액세스토큰, 리프레시 토큰이다. </p>
<p>그럼 이제 소셜로그인을 통해</p>
<p>유저 정보와 jwt 액세스토큰, 리프레시 토큰이 생성된다. </p>
<p>  그 뒤에 토큰 관리방법은 다양한 방법이 있어서 선택하면되지만</p>
<p>  리프레시 토큰의 생명주기가 긴 만큼 보안이 확실하게 관리하고</p>
<p>  액세스 토큰은 세션에서 관리하는게 편할 듯 하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflow project 27 - frontend vite 배포]]></title>
            <link>https://velog.io/@glory_joo/livflow-project-27-frontend-vite-%EB%B0%B0%ED%8F%AC</link>
            <guid>https://velog.io/@glory_joo/livflow-project-27-frontend-vite-%EB%B0%B0%ED%8F%AC</guid>
            <pubDate>Wed, 05 Feb 2025 17:08:49 GMT</pubDate>
            <description><![CDATA[<p>기존 프론트 컨테이너는 아래처럼 2개로 관리했었는데</p>
<pre><code>services:
  # 프론트엔드 빌드 서비스
  frontend:
    build:
      context: .  # 현재 디렉토리를 빌드 컨텍스트로 사용
      dockerfile: dockerfile  # 사용할 Dockerfile 지정
    container_name: frontend-container  # 컨테이너 이름
    volumes:
      #- build_volume:/usr/share/nginx/html  # Nginx 컨테이너에서 제공할 빌드 결과물 경로에 매핑
      - /etc/letsencrypt:/etc/letsencrypt:ro
#./dist:

  # Nginx 컨테이너
  frontend-nginx:
    image: nginx:1.23-alpine  # Nginx 이미지 사용
    container_name: frontend-nginx  # Nginx 컨테이너 이름
    ports:
      - &quot;80:80&quot;
      - &quot;443:443&quot;  
    volumes:
     # - build_volume:/usr/share/nginx/html
      - ./nginx.conf:/etc/nginx/nginx.conf
      - /etc/letsencrypt/archive/livflow.co.kr/fullchain2.pem:/etc/letsencrypt/live/livflow.co.kr/fullchain.pem
      - /etc/letsencrypt/archive/livflow.co.kr/privkey2.pem:/etc/letsencrypt/live/livflow.co.kr/privkey.pem
      - ./certbot:/var/www/certbot

volumes:
  build_volume:
    driver: local
    driver_opts:
      type: &quot;none&quot;
      device: &quot;./dist&quot;  # 빌드된 정적 파일들이 있는 경로를 지정
      o: &quot;bind&quot;</code></pre><p>  사실 만들때부터 1개로..해도되나...? 하면서 만들긴했다. </p>
<p>  백엔드만 배포해보다가 프론트엔드 배포를 처음해봐서 그런지 2개 컨테이너로 하는게 기본인가 했는데 역할을 생각해보면 1개여도 충분했었다. </p>
<p>  근데 이 부분이 배포에서 문제를 일으킬줄 몰랐다. 보면 frontend-container, frontend-nginx</p>
<p>이렇게 있는데 frontend-nginx가 배포해주는 .DIST가 있는 컨테이너다. 이게 분리되어 있다보니</p>
<p>CICD도 잘되고, 서버에 코드도 최신화가 되는데 배포 .DIST파일이 과거 파일이라 웹페이지가 이전꺼로 보이는 문제가 발생했다. 괜히 이것때문에 소셜로그인 고쳐본다고 시간만 버렸다. </p>
<p>어쨋든 통합컨테이너로 바꾼 뒤 문제는 사라져서 다행이다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[compose와 Kubernetes는 무슨 차이가 있지?]]></title>
            <link>https://velog.io/@glory_joo/compose%EC%99%80-Kubernetes%EB%8A%94-%EB%AC%B4%EC%8A%A8-%EC%B0%A8%EC%9D%B4%EA%B0%80-%EC%9E%88%EC%A7%80</link>
            <guid>https://velog.io/@glory_joo/compose%EC%99%80-Kubernetes%EB%8A%94-%EB%AC%B4%EC%8A%A8-%EC%B0%A8%EC%9D%B4%EA%B0%80-%EC%9E%88%EC%A7%80</guid>
            <pubDate>Wed, 29 Jan 2025 14:42:15 GMT</pubDate>
            <description><![CDATA[<p>compose와 Kubernetes는 무엇인가</p>
<table>
<thead>
<tr>
<th>항목</th>
<th>Docker Compose</th>
<th>Kubernetes</th>
</tr>
</thead>
<tbody><tr>
<td><strong>주요 목적</strong></td>
<td>여러 개의 컨테이너를 로컬에서 쉽게 관리</td>
<td>컨테이너의 배포, 확장, 자동 복구</td>
</tr>
<tr>
<td><strong>주 사용 환경</strong></td>
<td>개발 및 테스트 환경</td>
<td>프로덕션 및 대규모 서비스 환경</td>
</tr>
<tr>
<td><strong>구성 파일</strong></td>
<td><code>docker-compose.yml</code></td>
<td>YAML 파일 (Deployment, Service, Ingress 등)</td>
</tr>
<tr>
<td><strong>컨테이너 실행 방식</strong></td>
<td>단일 노드에서 여러 컨테이너 실행</td>
<td>여러 노드에서 컨테이너를 클러스터로 실행</td>
</tr>
<tr>
<td><strong>오케스트레이션 기능</strong></td>
<td>단순 컨테이너 실행 및 네트워킹</td>
<td>자동 확장, 로드 밸런싱, 헬스 체크, 자동 복구</td>
</tr>
<tr>
<td><strong>설치 난이도</strong></td>
<td>간단 (<code>docker-compose up -d</code>)</td>
<td>복잡 (쿠버네티스 클러스터 설정 필요)</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[gunicorn은 무엇인가?]]></title>
            <link>https://velog.io/@glory_joo/gunicorn%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</link>
            <guid>https://velog.io/@glory_joo/gunicorn%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80</guid>
            <pubDate>Wed, 29 Jan 2025 14:41:07 GMT</pubDate>
            <description><![CDATA[<p>gunicorn은 Python WSGI(웹 서버 게이트웨이 인터페이스) HTTP 서버로, Django나 Flask 같은 웹 프레임워크와 함께 사용하여 프로덕션 환경에서 안정적으로 애플리케이션을 실행하는 데 사용</p>
<p>이 gunicorn은 HTTP 요청을 받아서 Django 애플리케이션에 전달하고, 그 결과를 클라이언트에게 응답하는 역할을 한다. </p>
<p>장고를 예시로 들자면 장고를 실행할 수 있는 일반적인 방법은 3개이다. </p>
<p>하나는 로컬에서 테스트할때 많이 쓰는 runserver 다만 이건 단일스레드에 배포환경에서는 부적합하다. </p>
<p>두번째는 웹소켓을 사용할때 쓰는 uvicorn 이건 동기식 지원을 할때 쓴다. </p>
<p>그리고 세번째가 gunicorn이다. </p>
<p>uvicorn은     FastAPI, Starlette, Django ASGI에 많이 사용되고</p>
<p>Gunicorn은 Django, Flask에 많이 사용된다. </p>
<table>
<thead>
<tr>
<th>실행 방식</th>
<th>WSGI/ASGI</th>
<th>사용 목적</th>
<th>언제 사용해야 할까?</th>
</tr>
</thead>
<tbody><tr>
<td><code>runserver</code></td>
<td>WSGI</td>
<td>개발용</td>
<td>로컬에서 테스트할 때</td>
</tr>
<tr>
<td><code>uvicorn</code></td>
<td>ASGI</td>
<td>비동기</td>
<td>WebSocket, Django Channels 필요할 때</td>
</tr>
<tr>
<td><code>gunicorn</code></td>
<td>WSGI</td>
<td>운영 환경</td>
<td>실 서비스에서 배포할 때 (일반적)</td>
</tr>
</tbody></table>
<p>물론 이렇게 보다보면 장고에서 웹소켓을 사용할때 쓰는 daphen이랑 uvicorn이 비슷해 보일 수 있는데, </p>
<p>Daphne는 Django Channels와 함께 사용되도록 설계있기 때문에 장고 채널스를 쓰는 곳에서는 uvicorn이아니라 dahpen을 사용해야한다. 
uvicorn은 비동기 프레임워크에 사용하는 고성능 asgi서버이기 때문에 장고뿐아니라 다양한 곳에서 사용할 수 있고, FastAPI, Starlette에서 많이 사용한다. </p>
<p>도커를 사용하느라 구니콘은 그저 한,두줄만 사용해봐서 이런 기능이 있는지 몰랐는데</p>
<h2 id="결론">결론</h2>
<p>guicorn은 동기식 방식의 멀티프로세스가 가능한 파이썬 htttp서버로, nginx와 같이 사용하면 더 효과적으로 사용할 수 있고, </p>
<p>이와 비슷한 개념으로 uvicorn, daphen, runserver가 있지만 각각 사용하는 프로젝트들이 다르다. 알맞게 사용해야한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflow project 26일차 -redis container]]></title>
            <link>https://velog.io/@glory_joo/livflow-project-26%EC%9D%BC%EC%B0%A8-redis-container</link>
            <guid>https://velog.io/@glory_joo/livflow-project-26%EC%9D%BC%EC%B0%A8-redis-container</guid>
            <pubDate>Wed, 29 Jan 2025 05:08:04 GMT</pubDate>
            <description><![CDATA[<p>login을 구현할 때 token을 어떻게 할까 고민했다. </p>
<p>이전 프로젝트에서는 access token이랑 refresh token을 둘 다 쿠키로 전달했는데 refresh token은 쿠키로 전달하면 안된다고 들어서</p>
<p>이전에 멘토님이 조언해준대로 refresh token을 redis에 담아서 전달해볼까한다. </p>
<p>우선 서버가 NAS라서 모든 배포를 컨테이너로 하고있기 때문에</p>
<p>Redis를 사용하려면 redis 컨테이너가 필요해서 우선 컨테이너를 먼저 구성했다. </p>
<pre><code>
  redis:
    image: redis:latest  
    container_name: redis01  
    restart: always  
    ports:
      - &quot;6379:6379&quot;  
    networks:
      - app-network
    command: redis-server --appendonly yes  
    env_file: .env
</code></pre><p>   우선 컨테이너를 구성했고, redis에서 ping pong은 확인을 했는데 </p>
<p>   아직 토큰을 담고 전달하는 기능은 사용해본적이 없어서 어떤식으로 진행해야할지는 좀더 고민해봐야 할거같다. </p>
<p>   이걸로 컨테이너가 하나 더 늘어났다. 
   이제 7개 컨테이너인데 이게 경쟁력이 있는건지는 잘 모르겠다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflow project 25일차 - login page]]></title>
            <link>https://velog.io/@glory_joo/livflow-project-25%EC%9D%BC%EC%B0%A8</link>
            <guid>https://velog.io/@glory_joo/livflow-project-25%EC%9D%BC%EC%B0%A8</guid>
            <pubDate>Wed, 29 Jan 2025 05:07:22 GMT</pubDate>
            <description><![CDATA[<p>현재 홈페이지에 들어가면</p>
<p>login page에서 버튼 반응이 없는 문제가 발생했다. </p>
<p>고민해보다가 콘솔에 js를 .click으로 직접찍어보고 반응을 확인해보았는데</p>
<p>반응이 있는거로 봐서는 코드적으로는 버튼으로 문제가 있는건 아닌 듯 하다. </p>
<p>그렇다면 login hrf로 이동되지 않는 문제가 있는거 같은데</p>
<p>지금 내 생각으로는 backend login page로 제대로 연결이 안되는건가 싶어서 social login을 먼저 구현해놓아야 할 듯 하다. </p>
<p><img src="https://velog.velcdn.com/images/glory_joo/post/85bba707-21af-4fca-949b-b577972ff1b7/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[viewset과 apiview는 무엇일까?]]></title>
            <link>https://velog.io/@glory_joo/viewset%EA%B3%BC-apiview%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@glory_joo/viewset%EA%B3%BC-apiview%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Thu, 26 Dec 2024 09:40:07 GMT</pubDate>
            <description><![CDATA[<p>간단히 결론부터 말하면 다음과같다. </p>
<p>간단하게 할때 -&gt; viewset
복잡하게 할때 -&gt; apiview</p>
<h2 id="viewset이-적합한-경우">ViewSet이 적합한 경우</h2>
<h3 id="간단한-crud-중심-api">간단한 CRUD 중심 API:</h3>
<p>데이터베이스 모델과 직결된 CRUD 작업을 구현할 때, ViewSet과 ModelViewSet이 적합합니다.
URL 라우팅이 자동으로 처리되므로 코드가 간결하고 유지보수가 쉬워집니다.</p>
<h3 id="restful-api-설계">RESTful API 설계:</h3>
<p>RESTful 표준 동작(GET, POST, PUT, DELETE 등)을 따르는 경우, ViewSet은 빠르게 CRUD 기능을 구축할 수 있습니다.
커스텀 로직이 적음:</p>
<p>단순 CRUD 작업 외에 추가적인 로직이 거의 필요하지 않을 때 적합합니다.
예를 들어, 블로그 포스트, 사용자 관리 등의 단순한 API를 구축할 때.</p>
<h3 id="커스텀-로직이-적음">커스텀 로직이 적음:</h3>
<p>단순 CRUD 작업 외에 추가적인 로직이 거의 필요하지 않을 때 적합합니다.
예를 들어, 블로그 포스트, 사용자 관리 등의 단순한 API를 구축할 때.</p>
<h2 id="apiview가-적합한-경우">APIView가 적합한 경우</h2>
<h3 id="복잡한-비즈니스-로직">복잡한 비즈니스 로직:</h3>
<p>요청 처리 과정에서 데이터 검증, 외부 API 호출, 복잡한 계산 등이 필요할 때.
예를 들어, 주문 처리 로직, 동적 권한 부여, 상태 전이에 따른 동작 등이 포함된 경우.</p>
<h3 id="비표준-url-설계">비표준 URL 설계:</h3>
<p>RESTful 표준이 아닌 커스텀 URL이 필요하거나, Router로 처리할 수 없는 경로가 있는 경우.
예를 들어, /orders/<id>/confirm/와 같은 특정 동작이 포함된 API.</p>
<h3 id="http-메서드별-세부-제어-필요">HTTP 메서드별 세부 제어 필요:</h3>
<p>각 HTTP 메서드(GET, POST, PUT, DELETE)에서 동작을 세밀하게 제어해야 할 때.
예를 들어, POST 요청에서 특정 조건에 따라 다른 동작을 실행하거나, 응답 구조가 복잡한 경우.</p>
<h3 id="추가적인-인증권한-로직">추가적인 인증/권한 로직:</h3>
<p>기본 권한 설정 외에 복잡한 인증 및 권한 로직이 필요한 경우.</p>
<p>ViewSet은 데이터 모델과 관련된 CRUD 작업을 효율적으로 처리할 때 가장 적합하다. Router와 함께 사용하여 URL 라우팅을 자동화하고, RESTful API 설계를 간소화할 수 있다. </p>
<p>만약, 복잡한 비즈니스 로직이나 비표준 URL 설계가 필요하다면 APIView나 GenericAPIView를 사용하는 것이 더 나은 선택일 수 있다. 즉, 간단한 CRUD 중심 API를 개발할 때는 ViewSet이 가장 강력하고 효율적인 도구이지만, 로직이 복잡해질걸 예상한다면 apiview나 다른 커스텀 가능한 DRF를 쓰는게 유용할 듯 하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DRF란 무엇일까? serializer편]]></title>
            <link>https://velog.io/@glory_joo/DRF%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C-serializer%ED%8E%B8</link>
            <guid>https://velog.io/@glory_joo/DRF%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C-serializer%ED%8E%B8</guid>
            <pubDate>Thu, 26 Dec 2024 09:25:10 GMT</pubDate>
            <description><![CDATA[<p>DRF는 Django REST Framework이다. 
REST API를 편하게 장고에서 구현하기 위해 만든건데
많은 특징중에
시리얼라이저에 대해 알아보려고한다. </p>
<h2 id="serializer의-주요-역할">Serializer의 주요 역할</h2>
<h3 id="직렬화-serialization">직렬화 (Serialization):</h3>
<p>Python 객체(Queryset 등)를 JSON 데이터로 변환하여 클라이언트에 응답할 수 있게 합니다.</p>
<h3 id="역직렬화-deserialization">역직렬화 (Deserialization):</h3>
<p>클라이언트로부터 받은 JSON 데이터를 Python 객체로 변환하여 서버에서 처리할 수 있게 합니다.</p>
<h3 id="유효성-검사">유효성 검사:</h3>
<p>데이터를 변환하는 동시에, 데이터가 유효한지 확인하는 역할을 합니다.
필드의 형식, 값의 범위 등을 검증하고, 문제가 있을 경우 오류를 반환합니다.</p>
<p>기본 serializer와 modelserializer등 다양한 기능이 있는데
Django에서는 주로 model로 쓰는듯하다. 
시리얼라이저로 추가하면 모델인스턴스를 데이터베이스에 자동으로 저장해주는 편함이 있다. </p>
<p>is_valid()
validated_data
save()
error()과같은 메서드를 통해 유효성검사를 한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTTP 메서드란 무엇일까?]]></title>
            <link>https://velog.io/@glory_joo/HTTP-%EB%A9%94%EC%84%9C%EB%93%9C%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@glory_joo/HTTP-%EB%A9%94%EC%84%9C%EB%93%9C%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Thu, 26 Dec 2024 07:36:03 GMT</pubDate>
            <description><![CDATA[<p>HTTP 메서드는 클라이언트(웹 브라우저, 애플리케이션)가 서버에 어떤 동작을 요청할 때 사용하는 명령어이다.</p>
<p>주요 메서드에는 4가지가 있고</p>
<h3 id="1-get">1. GET</h3>
<p>서버에서 데이터를 조회하기 위해 사용.
데이터를 가져올 때 주로 사용되며, 서버의 상태를 변경하지 않음.
예시:
GET /users: 모든 사용자 조회
GET /users/1: 특정 사용자(ID 1) 조회</p>
<h3 id="2-post">2. POST</h3>
<p>서버에 데이터를 생성하거나 전송하기 위해 사용.
클라이언트가 요청 본문(body)에 데이터를 포함하여 전송.
예시:
POST /users: 새로운 사용자 생성</p>
<h3 id="3-put">3. PUT</h3>
<p>서버에서 특정 자원의 전체를 수정하거나 대체할 때 사용.
자원이 없으면 새로 생성할 수도 있음.
예시:
PUT /users/1: ID가 1인 사용자 정보 전체 수정</p>
<h3 id="4delete">4.DELETE</h3>
<p>서버에서 특정 자원을 삭제할 때 사용.
예시:
DELETE /users/1: ID가 1인 사용자 삭제</p>
<p>이외에도</p>
<h3 id="5-patch">5. PATCH</h3>
<p>자원의 일부를 수정할 때 사용.
PUT은 자원의 전체 교체를 수행하는 반면, PATCH는 필요한 필드만 변경.
예시:
PATCH /users/1: ID가 1인 사용자의 일부 정보 수정</p>
<h3 id="6-head">6. HEAD</h3>
<p>GET 요청과 유사하지만, 응답 본문(body)은 포함하지 않고 헤더만 반환.
자원의 존재 여부나 상태를 확인할 때 사용.
예시:
HEAD /users</p>
<h3 id="7-options">7. OPTIONS</h3>
<p>서버에서 지원하는 HTTP 메서드와 옵션을 확인.
예시:
OPTIONS /users</p>
<h3 id="8connect">8.CONNECT</h3>
<p>클라이언트와 서버 간의 터널을 설정하기 위해 사용.
주로 HTTPS 요청을 처리할 때 프록시 서버와 함께 사용.</p>
<h3 id="9trace">9.TRACE</h3>
<p>요청이 서버에 도달하는 경로를 디버깅하기 위해 사용.
실무에서는 보안 문제로 인해 거의 사용되지 않음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[REST란 무엇일까?]]></title>
            <link>https://velog.io/@glory_joo/REST%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@glory_joo/REST%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Thu, 26 Dec 2024 07:31:58 GMT</pubDate>
            <description><![CDATA[<p>REST란 HTTP기반의 아키텍쳐 스타일을 말한다. </p>
<p>이것을 위한 주요 원칙들이 있다. </p>
<p>REST의 주요 원칙</p>
<h3 id="1-자원resource-기반">1. 자원(Resource) 기반</h3>
<p>  웹의 모든 데이터는 &quot;자원(Resource)&quot;으로 간주됩니다.
  각 자원은 고유한 URI(Uniform Resource Identifier)로 식별됩니다.
  예: /users/1는 ID가 1인 사용자라는 자원을 나타냄.</p>
<h3 id="2-http-메서드의-활용">2. HTTP 메서드의 활용</h3>
<p>REST는 HTTP 메서드를 사용해 자원 조작 방식을 명확히 합니다:
GET: 자원을 조회
POST: 자원을 생성
PUT: 자원을 수정
DELETE: 자원을 삭제</p>
<h3 id="3-무상태성statelessness">3. 무상태성(Statelessness)</h3>
<p>서버는 클라이언트의 상태를 저장하지 않으며, 모든 요청은 독립적입니다.
클라이언트는 필요한 모든 정보를 요청에 포함해야 합니다.</p>
<h3 id="4-캐시-가능cacheable">4. 캐시 가능(Cacheable)</h3>
<p>응답은 캐시 가능해야 하며, HTTP 헤더를 통해 캐시 정책을 정의할 수 있습니다.</p>
<h3 id="5계층화layered-system">5.계층화(Layered System)</h3>
<p>클라이언트와 서버 간에 중간 계층(예: 로드 밸런서, 프록시)이 추가될 수 있지만, 클라이언트는 이를 알 필요가 없습니다.</p>
<h3 id="6--표현representation">6.  표현(Representation)</h3>
<p>자원은 JSON, XML, HTML 등 여러 형태로 클라이언트에게 전달될 수 있습니다.
자원의 상태는 이 표현을 통해 전달됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[RESTful API란 무엇일까?]]></title>
            <link>https://velog.io/@glory_joo/RESTful-API%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</link>
            <guid>https://velog.io/@glory_joo/RESTful-API%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C</guid>
            <pubDate>Thu, 26 Dec 2024 07:28:22 GMT</pubDate>
            <description><![CDATA[<p>많이 쓰이지만 잘 모르는 용어들에 대해 정리하는 
글이다. </p>
<p>Restful api</p>
<p>REST와 RESTful은 웹 API 설계 및 구현에서 자주 언급되는 개념이다. </p>
<p>REST : Representational State Transfer</p>
<p>REST는 <strong>아키텍처 스타일(Architectural Style)</strong>입니다. 웹 서비스 설계의 원칙과 제약 조건을 정의하는 일종의 가이드라인으로, HTTP기반으로 표현하고 조작하는데 중점을 둔다. </p>
<p>여기서 아키텍쳐 스타일은 소프트웨어 시스템의 구조를 설계하기 위한 패턴이나 가이드라인을 의미한다. </p>
<p>RESTFUL 이란건 이런 REST한 아키텍쳐 스타일을 잘 적용한 것을 뜻하는 말이다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[livflow project 24일차 - 정적파일 오류]]></title>
            <link>https://velog.io/@glory_joo/livflow-project-24%EC%9D%BC%EC%B0%A8-%EC%A0%95%EC%A0%81%ED%8C%8C%EC%9D%BC-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@glory_joo/livflow-project-24%EC%9D%BC%EC%B0%A8-%EC%A0%95%EC%A0%81%ED%8C%8C%EC%9D%BC-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Thu, 19 Dec 2024 12:25:31 GMT</pubDate>
            <description><![CDATA[<p>무슨 프로젝트가 오류밖에 안나온다.</p>
<p>한 서버에 2개를 배포하려니까 더 문제가 되는거같다. </p>
<p>하나하나 해결하기 위해 우선 swagger가 안들어가지는 문제를 해결하려고한다. </p>
<p>백엔드 주소로 들어갓는데</p>
<p>/swagger에 접속을 하니 정적파일이 안뜬다. </p>
<p>/admin에 들어가니 거기도 정적파일이 안뜬다. </p>
<p>/portainer에 들어가니 이건 외부 프로그램이라 그런지 잘뜬다. </p>
<p>그렇다면 어디 정적파일이 문제인거같은데..</p>
<pre><code>swagger/    200    document    swagger    2.8 kB    13밀리초
swagger    200    document / 리디렉션    기타    (디스크 캐시)    대기 중
swagger-ui.css    404    stylesheet    swagger/:18    155 B    11밀리초
swagger-ui-bundle.js    404    script    swagger/:41    155 B    11밀리초
swagger-ui-standalone-preset.js    404    script    swagger/:42    155 B    15밀리초
insQ.min.js    404    script    swagger/:43    155 B    15밀리초
immutable.min.js    404    script    swagger/:44    155 B    15밀리초
swagger-ui-init.js    404    script    swagger/:45    155 B    23밀리초
contentscript.js    200    script    inject.js:82    4.9 kB    10밀리초
style.css    404    stylesheet    swagger/:17    155 B    13밀리초
contentscript.js    200    script    inject.js:82    4.8 kB    9밀리초</code></pre><p>이런 문제가 보였는데</p>
<p>딱봐도 정적파일이 어디 있거나 없거나 하는 상황에 사이트에 접속하면 이 정적파일로 안내가 안되는 듯 했다. </p>
<p>그렇다면 확인할 문제는 몇개 있다. </p>
<p>정적파일은 있는가?</p>
<p>정적파일은 어디에 있는가?</p>
<p>정적파일이 잘 마운트 되고 있는가?</p>
<p>이렇게 확인을 하면 될 것 같았다. </p>
<h3 id="정적파일은-있는가">정적파일은 있는가?</h3>
<pre><code>joo@liv:~$ docker exec -it liv_pro ls /app/staticfiles/drf-yasg
README          insQ.js      redoc-init.js  swagger-ui-dist
immutable.js      insQ.min.js  redoc-old      swagger-ui-init.js
immutable.min.js  redoc        style.css</code></pre><p>있다. 우선 app에는 있다. </p>
<h3 id="정적파일은-어디에-있는가">정적파일은 어디에 있는가?</h3>
<p>위치를 보면 app/staticfiles에 있다. collectstatic이 잘된거같다. </p>
<h3 id="정적파일은-잘-마운트-되고-있는가">정적파일은 잘 마운트 되고 있는가?</h3>
<p>이 부분을 확인하려고 어떻게 할지 고민하다가 gamebox에서 파일을 마운트해서 배포하단걸 기억하고</p>
<p>nginx에 파일이 있는지 확인해보았다. </p>
<pre><code>joo@livdocker exec -it ng01 ls /app/staticfiles/drf-yasgyasg
ls: /app/staticfiles/drf-yasg: No such file or directory</code></pre><p>파일이 없다</p>
<p>맙소사</p>
<p>그러면 잘 컨테이너화 되서 nginx에 저 파일로 마운트를 시도했으나 그게 실패한거같다/ </p>
<h3 id="마운트-방법은">마운트 방법은?</h3>
<p>당연히 docker compose로 가보자.</p>
<pre><code>  - ./nginx.conf:/etc/nginx/nginx.conf
  - /etc/letsencrypt:/etc/letsencrypt
  - ./certbot:/var/www/certbot  # 인증서 발급을 위한 볼륨 추가
  - static_volume:/app/static
  - media_volume:/app/media</code></pre><p> 보면 static 파일로 마운트가 되고 있었다. </p>
<pre><code>   - ./pyproject.toml:/app/pyproject.toml:ro
  - ./poetry.lock:/app/poetry.lock:ro
  - ./django:/app/django
  - /home/joo/back-end-coffee/django/logs:/home/joo/back-end-coffee/django/logs 
  - static_volume:/app/django/static
  - media_volume:/app/django/media</code></pre><p> web에서도 보면 장고 스태틱 파일로 마운트 중이다. </p>
<p> 이부분이 debug true일땐 문제가 없었지만 false일때 문제가 된 부분인듯하다. </p>
<p> 이부분을 전부 staticfile로 수정해주니 문제가 해결되었다. </p>
]]></description>
        </item>
    </channel>
</rss>