<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>study coding.log</title>
        <link>https://velog.io/</link>
        <description>개발언어를 배우는 과정 기록</description>
        <lastBuildDate>Sat, 06 Jun 2026 08:49:53 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>study coding.log</title>
            <url>https://velog.velcdn.com/images/hy_1023/profile/b1866f26-eb60-4a31-8fcb-5daca3ac7482/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. study coding.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hy_1023" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[20260606_4차프로젝트진행중 ]]></title>
            <link>https://velog.io/@hy_1023/202606064%EC%B0%A8%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%A7%84%ED%96%89%EC%A4%91</link>
            <guid>https://velog.io/@hy_1023/202606064%EC%B0%A8%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%A7%84%ED%96%89%EC%A4%91</guid>
            <pubDate>Sat, 06 Jun 2026 08:49:53 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hy_1023/post/86896231-7601-41b2-94f9-fbee16521cda/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/cf1bf85b-5c8c-47d8-a1b4-aa314bc668a5/image.png" alt=""></p>
<p>현재 클로드 사용을 하며 에이전트 까지 해보고싶었지만  프로젝트 기획에서 </p>
<p>시간을 너무 많이 지연되어 사부작사부작을 여유있게 못해서 마감일까지 한루</p>
<p>프를 제대로 핵심적으로 구현이 목표이고  그후  내가 하고자 했던 기능들을 </p>
<p>개발용  배표용  두가지로 나누고  현업스타일로 제대로 한번 만들어 볼생각</p>
<p>우선 핵심 뽀인트! 깐딴하게 니즈!!!!에 충실한 부분을 쏙빼서 만드는 중</p>
<p>17일이후부터  아마  수정할부분 수정하고 제대로  개발용 배포용 나눠서 </p>
<p>작업할생각이고  우선 사람들의 반응 이게 정말 필요한건가 ? </p>
<p>내가 느낀 필요성을  다른사람들도 필요하다고 생각하나? </p>
<p>그리고 필요성들  needs에 대한 부분에 충족을 조금이라도  도움이 됐을까?</p>
<p>를 눈으로 확인하고 싶어 배포를 최대한 빨리 해볼생각입니다! </p>
<p>확장성을 가지고 하는것이기에 급하지만 길게 보고 가는 프로젝트! </p>
<p>과연 구현이 될까 도움이 될까 내가 그 만큼 퀄리티와 핵심을 파악할수있을까</p>
<p>내가 삶을 살면서 깨달은 한가지 확실한것은 진실된 마음은 통한다는것이고 . </p>
<p>(언젠가는)  지금 당장이 아니더라도 ..</p>
<p>기획은 항상 복붙이 많기에 이것을 누가 ctrl+C  ctrl+V  를 한들  </p>
<p>마음은 아프겠지만  </p>
<p>좋은 영향력이  되었으면 하는 마음을 이프로젝트를 만드는중여서 </p>
<p>이왕한거 내가 이걸 왜 기획했고 선한영향력을 주는 분들이 돋보여야하는데 그</p>
<p>렇지 않다는 현실이 너무 그러하여 앞으로 이 프로젝트 외에도 </p>
<p>다른분야에 선한영향력을 주시며 묵묵히 일하시는 분들을 위해 조금의 도움이</p>
<p>된다면 브릿지 연결고리역할을 하는 그런 프로젝트를 만들고 싶네요</p>
<p>모두 다  윈윈으로 가는 방향 :)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트마감2주전]]></title>
            <link>https://velog.io/@hy_1023/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A7%88%EA%B0%902%EC%A3%BC%EC%A0%84</link>
            <guid>https://velog.io/@hy_1023/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EB%A7%88%EA%B0%902%EC%A3%BC%EC%A0%84</guid>
            <pubDate>Sun, 31 May 2026 07:50:00 GMT</pubDate>
            <description><![CDATA[<p>기록용</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[모각코란..?]]></title>
            <link>https://velog.io/@hy_1023/%EB%AA%A8%EA%B0%81%EC%BD%94%EB%9E%80-y8ubahir</link>
            <guid>https://velog.io/@hy_1023/%EB%AA%A8%EA%B0%81%EC%BD%94%EB%9E%80-y8ubahir</guid>
            <pubDate>Sun, 17 May 2026 05:44:57 GMT</pubDate>
            <description><![CDATA[<p><a href="https://discord.gg/qh8PrEY5u">https://discord.gg/qh8PrEY5u</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[도메인 ]]></title>
            <link>https://velog.io/@hy_1023/%EB%8F%84%EB%A9%94%EC%9D%B8</link>
            <guid>https://velog.io/@hy_1023/%EB%8F%84%EB%A9%94%EC%9D%B8</guid>
            <pubDate>Sun, 17 May 2026 05:36:56 GMT</pubDate>
            <description><![CDATA[<hr>
<h3 id="1-도메인-구매-나만의-주소">1. 도메인 구매 (나만의 주소)</h3>
<p><code>heropy.dev</code>나 <code>naver.com</code> 같은 주소를 도메인(Domain)이라고 합니다.</p>
<ul>
<li>가비아, 후이즈, 고대디(GoDaddy), 레지스트리닷컴 같은 <strong>도메인 대행업체</strong>에서 1년에 약 1~3만 원 정도의 비용을 내고 원하는 이름을 구매합니다.</li>
<li>특히 개발자나 디자이너분들은 <code>.com</code> 외에도 <code>.dev</code>, <code>.io</code>, <code>.me</code> 같은 개성 있는 확장자를 많이 선호합니다.</li>
</ul>
<h3 id="2-호스팅-혹은-배포-서비스-실제-파일-저장소">2. 호스팅 혹은 배포 서비스 (실제 파일 저장소)</h3>
<p>도메인만 산다고 사이트가 짠 하고 나타나지는 않습니다. 우리가 만든 HTML, CSS, JavaScript, 이미지 파일 등을 24시간 켜져 있는 컴퓨터(서버)에 올려두어야 하는데, 이를 <strong>호스팅</strong> 또는 <strong>배포</strong>라고 합니다.</p>
<ul>
<li>요즘은 <strong>Vercel, Netlify, GitHub Pages</strong> 같은 서비스를 많이 이용합니다.</li>
<li>심지어 이 서비스들은 취미나 개인 포트폴리오 수준에서는 <strong>대부분 무료</strong>로 서버를 제공해 줍니다. (이 사이트 하단을 보니 <code>SvelteKit</code>이라는 프레임워크로 만들어진 것 같네요!)</li>
</ul>
<h3 id="3-도메인-연결-네임서버-설정">3. 도메인 연결 (네임서버 설정)</h3>
<p>구매한 도메인(예: <code>내이름.dev</code>)과 배포한 서버의 주소를 연결해 주는 작업을 합니다. 이 설정을 마치면 전 세계 어디서든 해당 도메인을 입력했을 때 내 포트폴리오 사이트로 연결됩니다.</p>
<hr>
<blockquote>
<p>💡 <strong>한 줄 요약</strong>
서버에 파일을 올리는 것 자체는 <strong>무료 서비스(Vercel, GitHub 등)</strong>로 해결할 수 있지만, <code>xxxx.dev</code> 같은 깔끔한 개인 주소를 쓰기 위해 <strong>도메인만 따로 구매해서 연결한 것</strong>이라고 보시면 됩니다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[20260513_broker_detail.html]]></title>
            <link>https://velog.io/@hy_1023/20260513brokerdetail.html</link>
            <guid>https://velog.io/@hy_1023/20260513brokerdetail.html</guid>
            <pubDate>Wed, 13 May 2026 01:56:58 GMT</pubDate>
            <description><![CDATA[<p>{% extends &quot;base.html&quot; %}</p>
<p>{% block title %}{{ agent.bsnm_cmpnm }} - 상세정보{% endblock %}</p>
<p>{% block content %}</p>
<p>{# JS 가 읽을 설정값 — 인라인 JS 없이 완전 분리 #}</p>
<script id="pageConfig" type="application/json">
{
  "csrfToken"       : "{{ csrf_token }}",
  "uploadUrl"       : "{% url 'brokers:broker_image_upload' agent.pk %}",
  "imageDeleteBase" : "{% url 'brokers:broker_image_delete' 0 %}",
  "reviewDeleteBase": "{% url 'interactions:review_delete' 0 %}"
}
</script>

<div class="page-wrap">

<p>  <a href="{% url 'brokers:broker1_list' %}" class="back-btn">← 목록으로</a></p>
  <div class="detail-header">

<pre><code>&lt;div class=&quot;rep-image&quot; id=&quot;repImageBox&quot;&gt;

  {% if images %}

    {% with primary_img=images|dictsort:&quot;is_primary&quot;|last %}
      &lt;img id=&quot;repImg&quot;
           src=&quot;{% if primary_img %}{{ primary_img.image.url }}{% else %}{{ images.0.image.url }}{% endif %}&quot;
           alt=&quot;{{ agent.bsnm_cmpnm }}&quot;&gt;
    {% endwith %}

    {% if user.is_authenticated %}
      &lt;div class=&quot;img-overlay&quot;&gt;
        &lt;button class=&quot;overlay-btn&quot; id=&quot;btnShowChangePanel&quot;&gt;📷 사진 변경&lt;/button&gt;
        {% for img in images %}
          {% if img.uploaded_by == user or user.is_staff %}
            &lt;button class=&quot;overlay-btn btn-img-delete&quot;
                    data-img-pk=&quot;{{ img.pk }}&quot;
                    style=&quot;background:rgba(220,38,38,.88);color:#fff;&quot;&gt;
              🗑 삭제
            &lt;/button&gt;
          {% endif %}
        {% endfor %}
      &lt;/div&gt;

      &lt;div class=&quot;upload-panel&quot; id=&quot;changePanel&quot;&gt;
        &lt;button class=&quot;panel-close&quot; id=&quot;btnCloseChangePanel&quot; type=&quot;button&quot;&gt;✕&lt;/button&gt;
        &lt;input type=&quot;file&quot; id=&quot;changeFileInput&quot; accept=&quot;image/*&quot; class=&quot;d-none&quot;&gt;
        &lt;label for=&quot;changeFileInput&quot; class=&quot;upload-trigger compact&quot;&gt;
          &lt;span class=&quot;upload-icon&quot;&gt;📷&lt;/span&gt;
          &lt;span class=&quot;upload-text&quot;&gt;파일 선택&lt;/span&gt;
        &lt;/label&gt;
        &lt;p class=&quot;file-name-preview&quot; id=&quot;changeFileName&quot;&gt;&lt;/p&gt;
        &lt;input type=&quot;text&quot; id=&quot;changeCaptionInput&quot;
               placeholder=&quot;사진 설명 (선택)&quot;
               class=&quot;form-control form-control-sm mt-1 mb-2&quot;&gt;
        &lt;button type=&quot;button&quot; class=&quot;btn btn-primary btn-sm w-100&quot; id=&quot;btnSubmitChange&quot;&gt;업로드&lt;/button&gt;
        &lt;div class=&quot;upload-feedback&quot; id=&quot;changeFeedback&quot;&gt;&lt;/div&gt;
      &lt;/div&gt;
    {% endif %}

  {% else %}

    {% if user.is_authenticated %}
      &lt;input type=&quot;file&quot; id=&quot;newFileInput&quot; accept=&quot;image/*&quot; class=&quot;d-none&quot;&gt;
      &lt;label for=&quot;newFileInput&quot; class=&quot;upload-trigger&quot; id=&quot;newUploadTrigger&quot;&gt;
        &lt;span class=&quot;upload-icon&quot;&gt;📷&lt;/span&gt;
        &lt;span class=&quot;upload-text&quot;&gt;사진 추가하기&lt;/span&gt;
        &lt;span class=&quot;upload-hint&quot;&gt;클릭하여 이미지 선택&lt;/span&gt;
      &lt;/label&gt;
      &lt;div class=&quot;upload-panel inline-style&quot; id=&quot;newUploadPanel&quot;&gt;
        &lt;p class=&quot;file-name-preview&quot; id=&quot;newFileName&quot;&gt;&lt;/p&gt;
        &lt;div class=&quot;progress-wrap&quot; id=&quot;newProgressWrap&quot;&gt;
          &lt;div class=&quot;progress&quot; style=&quot;height:5px;&quot;&gt;
            &lt;div id=&quot;newProgressBar&quot; class=&quot;progress-bar bg-primary&quot; style=&quot;width:0%;&quot;&gt;&lt;/div&gt;
          &lt;/div&gt;
          &lt;span id=&quot;newProgressText&quot; class=&quot;progress-text&quot;&gt;0%&lt;/span&gt;
        &lt;/div&gt;
        &lt;input type=&quot;text&quot; id=&quot;newCaptionInput&quot;
               placeholder=&quot;사진 설명 (선택)&quot;
               class=&quot;form-control form-control-sm mb-2&quot;&gt;
        &lt;button type=&quot;button&quot; class=&quot;btn btn-primary btn-sm w-100&quot; id=&quot;btnSubmitNew&quot;&gt;업로드&lt;/button&gt;
        &lt;button type=&quot;button&quot; class=&quot;btn btn-outline-secondary btn-sm w-100 mt-1&quot; id=&quot;btnCancelNew&quot;&gt;취소&lt;/button&gt;
        &lt;div class=&quot;upload-feedback&quot; id=&quot;newFeedback&quot;&gt;&lt;/div&gt;
      &lt;/div&gt;
    {% else %}
      &lt;div class=&quot;img-placeholder&quot;&gt;
        &lt;span class=&quot;icon&quot;&gt;🏢&lt;/span&gt;
        &lt;span&gt;등록된 사진 없음&lt;/span&gt;
      &lt;/div&gt;
    {% endif %}

  {% endif %}

&lt;/div&gt;

&lt;div class=&quot;header-right&quot;&gt;
  &lt;div class=&quot;header-top&quot;&gt;
    &lt;span class=&quot;broker-name&quot;&gt;{{ agent.bsnm_cmpnm }}&lt;/span&gt;
    {% if agent.sttus_se_code == &quot;1&quot; %}
      &lt;span class=&quot;status-badge open&quot;&gt;● 영업중&lt;/span&gt;
    {% else %}
      &lt;span class=&quot;status-badge closed&quot;&gt;폐업&lt;/span&gt;
    {% endif %}
  &lt;/div&gt;

  &lt;div class=&quot;info-grid&quot;&gt;
    &lt;div class=&quot;info-item&quot;&gt;
      &lt;div class=&quot;lbl&quot;&gt;등록번호&lt;/div&gt;
      &lt;div class=&quot;val&quot;&gt;{{ agent.jurirno|default:&quot;-&quot; }}&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;info-item&quot;&gt;
      &lt;div class=&quot;lbl&quot;&gt;대표자&lt;/div&gt;
      &lt;div class=&quot;val&quot;&gt;{{ agent.brkr_nm|default:&quot;-&quot; }}&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;info-item&quot;&gt;
      &lt;div class=&quot;lbl&quot;&gt;시군구&lt;/div&gt;
      &lt;div class=&quot;val&quot;&gt;{{ agent.ld_code_nm|default:&quot;-&quot; }}&lt;/div&gt;
    &lt;/div&gt;
    &lt;hr class=&quot;info-divider&quot;&gt;
    &lt;div class=&quot;info-item full-width&quot;&gt;
      &lt;div class=&quot;lbl&quot;&gt;도로명주소&lt;/div&gt;
      &lt;div class=&quot;val&quot;&gt;{{ agent.rdnmadr|default:&quot;-&quot; }}&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;info-item full-width&quot;&gt;
      &lt;div class=&quot;lbl&quot;&gt;지번주소&lt;/div&gt;
      &lt;div class=&quot;val&quot;&gt;{{ agent.mnnmadr|default:&quot;-&quot; }}&lt;/div&gt;
    &lt;/div&gt;
    &lt;hr class=&quot;info-divider&quot;&gt;
    &lt;div class=&quot;info-item&quot;&gt;
      &lt;div class=&quot;lbl&quot;&gt;등록일&lt;/div&gt;
      &lt;div class=&quot;val&quot;&gt;{{ agent.regist_de|default:&quot;-&quot; }}&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;info-item&quot;&gt;
      &lt;div class=&quot;lbl&quot;&gt;영업 시작일&lt;/div&gt;
      &lt;div class=&quot;val&quot;&gt;{{ agent.estbs_begin_de|default:&quot;-&quot; }}&lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=&quot;info-item&quot;&gt;
      &lt;div class=&quot;lbl&quot;&gt;영업 종료일&lt;/div&gt;
      &lt;div class=&quot;val&quot;&gt;{{ agent.estbs_end_de|default:&quot;-&quot; }}&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</code></pre>  </div>

  <div class="rating-card">
    <div>
      <div class="rating-big">{{ avg_score|default:"0" }}</div>
      <div class="rating-stars">
        {% for i in "12345" %}
          {% if forloop.counter <= avg_score %}★{% else %}☆{% endif %}
        {% endfor %}
      </div>
      <div class="rating-sub">리뷰 {{ review_count }}건</div>
    </div>
    <div class="rating-bar-wrap">
      {% for item in score_distribution %}
        <div class="rating-bar-row">
          <span>{{ item.score }}점</span>
          <div class="rating-bar-bg">
            <div class="rating-bar-fill"></div>
          </div>
          <span>{{ item.count }}</span>
        </div>
      {% empty %}
        {% for s in "54321" %}
          <div class="rating-bar-row">
            <span>{{ s }}점</span>
            <div class="rating-bar-bg">
              <div class="rating-bar-fill" style="width:0%"></div>
            </div>
            <span>0</span>
          </div>
        {% endfor %}
      {% endfor %}
    </div>
  </div>

<p>  {% if user.is_authenticated %}
    <a href="{% url 'interactions:review_create' agent.pk %}" class="btn-write-review">
      ✏️ 후기 작성하기
    </a>
  {% else %}
    <a href="{% url 'login' %}?next={{ request.path }}" class="btn-write-review disabled">
      🔒 로그인 후 후기 작성 가능
    </a>
  {% endif %}</p>
  <div class="review-title">
    💬 이용 후기
    <span class="count-chip" id="reviewCountChip">{{ review_count }}건</span>
  </div>

  <div id="reviewList">
    {% for review in reviews %}
      <div class="review-card" id="review-{{ review.pk }}">
        <div class="d-flex justify-content-between align-items-center">
          <div class="d-flex align-items-center gap-2">
            <span class="rv-author">{{ review.author.username }}</span>
            <span class="rv-stars">
              {% for i in "12345" %}
                {% if forloop.counter <= review.score %}★{% else %}☆{% endif %}
              {% endfor %}
            </span>
            <span class="rv-score">{{ review.score }}점</span>
          </div>
          <span class="rv-date">{{ review.created_at|date:"Y.m.d" }}</span>
        </div>
        <p class="rv-content">{{ review.content }}</p>
        {% if review.author == request.user %}
          <div class="text-end mt-2">
            <a href="{% url 'interactions:review_update' review.pk %}"
               class="btn btn-outline-primary btn-sm me-1"
               style="font-size:12px;">수정</a>
            <button type="button"
                    class="btn btn-outline-danger btn-sm btn-review-delete"
                    data-review-pk="{{ review.pk }}"
                    style="font-size:12px;">삭제</button>
          </div>
        {% endif %}
      </div>
    {% empty %}
      <div class="no-review" id="noReviewBox">
        <span class="icon">💬</span>
        <p class="mb-0 fw-semibold">아직 등록된 후기가 없습니다</p>
        <p class="small mt-1">첫 번째 후기를 작성해보세요!</p>
      </div>
    {% endfor %}
  </div>

</div>
{% endblock %}

<p>{% block extra_js %}</p>
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.8/dist/axios.min.js"></script>
<script src="{% static 'js/brokers/broker_detail.js' %}"></script>
<p>{% endblock %}</p>
<p><code>broker_detail.html</code>에서 <code>{% static &#39;js/brokers/broker_detail.js&#39; %}</code> 를 사용하고 있는데, 맨 위에 <code>{% load static %}</code> 가 선언되지 않으면 Django 템플릿 엔진이 <code>static</code> 태그를 인식하지 못해서 <code>TemplateSyntaxError</code>가 발생합니다. </p>
<p>현재 파일 상단은 이렇게 시작합니다:</p>
<pre><code class="language-django">{% extends &quot;base.html&quot; %}</code></pre>
<p>여기에 바로 아래 줄로 추가해야 합니다:</p>
<pre><code class="language-django">{% extends &quot;base.html&quot; %}
{% load static %}</code></pre>
<p>즉 최종 수정:</p>
<pre><code class="language-django">{% extends &quot;base.html&quot; %}
{% load static %}

{% block title %}{{ agent.bsnm_cmpnm }} - 상세정보{% endblock %}</code></pre>
<p>발생하는 대표 에러 메시지는 보통 아래 형태입니다:</p>
<pre><code class="language-python">TemplateSyntaxError: Invalid block tag on line XX: &#39;static&#39;</code></pre>
<p>원인:</p>
<ul>
<li><code>{% static %}</code> 사용</li>
<li>하지만 <code>{% load static %}</code> 없음</li>
</ul>
<p>추가로 이 파일에서는 아래 부분 때문에 반드시 필요합니다:</p>
<pre><code class="language-django">&lt;script src=&quot;{% static &#39;js/brokers/broker_detail.js&#39; %}&quot;&gt;&lt;/script&gt;</code></pre>
<p>따라서 핵심 원인은 정확히:</p>
<blockquote>
<p><code>static</code> template tag 미로드 (<code>{% load static %}</code> 누락) 입니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[팁]]></title>
            <link>https://velog.io/@hy_1023/%ED%8C%81</link>
            <guid>https://velog.io/@hy_1023/%ED%8C%81</guid>
            <pubDate>Wed, 13 May 2026 01:11:29 GMT</pubDate>
            <description><![CDATA[<p>이건 코드 문제가 아니라 <strong>VS Code 확장자 “Error Lens” 때문에 크게 표시되는 것</strong>입니다.</p>
<p>해결 방법:</p>
<ol>
<li>왼쪽 Extensions에서 <strong>Error Lens</strong> 클릭</li>
<li>톱니바퀴 클릭</li>
<li><strong>Disable</strong> 또는 <strong>Uninstall</strong></li>
</ol>
<p>또는 설정에서 숨길 수 있습니다.</p>
<p>VS Code <code>settings.json</code> 열고 아래 추가하세요:</p>
<pre><code class="language-json">&quot;errorLens.enabled&quot;: false</code></pre>
<p>Error Lens는 끄지 않고 큰 글씨만 숨기려면:</p>
<pre><code class="language-json">&quot;errorLens.messageEnabled&quot;: false</code></pre>
<p>그리고 <code>&quot;Kakao&quot;: Unknown word.</code> 자체는 <strong>Spell Checker / 맞춤법 검사 확장자</strong>가 <code>Kakao</code>를 모르는 단어로 판단해서 생긴 경고입니다.
단어만 등록하려면 Quick Fix에서:</p>
<pre><code class="language-text">Add: &quot;Kakao&quot; to workspace settings</code></pre>
<p>를 누르면 됩니다.</p>
<p>정리하면:</p>
<pre><code class="language-json">&quot;errorLens.messageEnabled&quot;: false,
&quot;cSpell.words&quot;: [
  &quot;Kakao&quot;
]</code></pre>
<hr>
<p>네 맞습니다. 현재 보이는 <code>{ ... }</code> 안에 추가하면 됩니다.</p>
<p>지금 상태에서 이렇게 수정하세요:</p>
<pre><code class="language-json">{
    &quot;editor.fontFamily&quot;: &quot;&#39;D2Coding&#39;,Consolas, &#39;Courier New&#39;, monospace&quot;,
    &quot;editor.renderControlCharacters&quot;: false,
    &quot;markdown-pdf.convertOnSave&quot;: true,
    &quot;markdown-pdf.breaks&quot;: true,
    &quot;python.createEnvironment.contentButton&quot;: &quot;show&quot;,
    &quot;eslint.rules.customizations&quot;: [],
    &quot;prettier.bracketSameLine&quot;: true,

    &quot;errorLens.messageEnabled&quot;: false
}</code></pre>
<p>주의:</p>
<ul>
<li>바로 위 줄 끝에 <code>,</code> 쉼표 추가해야 합니다.</li>
<li>마지막 줄에는 쉼표 넣지 않습니다.</li>
</ul>
<p>저장하면 (<code>Ctrl + S</code>) 큰 글씨가 바로 사라집니다.</p>
<hr>
<p><code>errorLens.messageEnabled</code>가 적용되지 않는 경우는 보통 아래 둘 중 하나입니다.</p>
<ol>
<li>VS Code 재시작이 안 됨</li>
<li>실제 큰 글씨는 <code>Code Lens</code> 기능임</li>
</ol>
<p>지금 설정에 이것도 추가해보세요:</p>
<pre><code class="language-json">&quot;errorLens.enabled&quot;: false</code></pre>
<p>전체 예시:</p>
<pre><code class="language-json">{
  &quot;editor.fontFamily&quot;: &quot;&#39;D2Coding&#39;, &#39;Courier New&#39;, monospace&quot;,
  &quot;editor.renderControlCharacters&quot;: false,
  &quot;markdown-pdf.convertOnSave&quot;: true,
  &quot;markdown-pdf.breaks&quot;: true,
  &quot;python.createEnvironment.contentButton&quot;: &quot;show&quot;,
  &quot;eslint.rules.customizations&quot;: [],
  &quot;prettier.bracketSameLine&quot;: true,

  &quot;errorLens.messageEnabled&quot;: false,
  &quot;errorLens.enabled&quot;: false
}</code></pre>
<p>저장 후:</p>
<pre><code class="language-text">Ctrl + Shift + P
→ Reload Window</code></pre>
<p>입력해서 VS Code 새로고침하세요.</p>
<hr>
<p>만약 그래도 남아있으면 범인은 <code>Code Lens</code> 입니다.
아래도 추가하세요:</p>
<pre><code class="language-json">&quot;errorLens.codeLensEnabled&quot;: false</code></pre>
<p>최종 추천:</p>
<pre><code class="language-json">&quot;errorLens.enabled&quot;: false,
&quot;errorLens.messageEnabled&quot;: false,
&quot;errorLens.codeLensEnabled&quot;: false</code></pre>
<p>이렇게 하면 화면 위에 뜨는 큰 경고 문구가 완전히 사라집니다.</p>
<hr>
<p>MCP는 <strong>Model Context Protocol</strong>의 약자입니다.</p>
<p>간단히 말하면:</p>
<blockquote>
<p>AI(Claude, ChatGPT 등)가 외부 도구·DB·파일·API와 연결되도록 하는 표준 프로토콜입니다.</p>
</blockquote>
<p>지금 VS Code에 보이는 <code>MCP Servers</code>는
AI 코딩 도구가 외부 기능을 사용할 수 있게 연결하는 기능입니다.</p>
<p>예를 들면 MCP로 AI가:</p>
<ul>
<li>PostgreSQL/MySQL 조회</li>
<li>로컬 파일 읽기</li>
<li>GitHub API 호출</li>
<li>브라우저 자동화</li>
<li>Figma 데이터 읽기</li>
<li>사내 문서 검색</li>
<li>터미널 명령 실행</li>
</ul>
<p>같은 걸 할 수 있습니다.</p>
<hr>
<p>예시 구조:</p>
<pre><code class="language-text">VS Code + Claude
        ↓
    MCP Client
        ↓
    MCP Server
        ↓
DB / API / Files / Tools</code></pre>
<hr>
<p>왜 생겼냐면:</p>
<p>기존 AI는 채팅만 가능했는데,
MCP를 쓰면 실제 개발도구와 연결되어:</p>
<ul>
<li>코드 수정</li>
<li>DB 조회</li>
<li>테스트 실행</li>
<li>파일 생성</li>
</ul>
<p>같은 작업을 자동화할 수 있습니다.</p>
<hr>
<p>지금 화면의 MCP Servers는:</p>
<pre><code class="language-text">&quot;AI가 사용할 외부 도구를 연결하는 서버 목록&quot;</code></pre>
<p>입니다.</p>
<p>아직 프리뷰 기능이라 설치 안 해도 됩니다.</p>
<hr>
<p>만약 관심 있으면 다음도 가능합니다:</p>
<ul>
<li>VS Code에서 MCP 서버 설치법</li>
<li>Claude + MCP + PostgreSQL 연결</li>
<li>로컬 파일 시스템 MCP 만들기</li>
<li>Python MCP 서버 예제</li>
<li>Cursor/Claude Code MCP 차이점</li>
</ul>
<p>원하면 이어서 설명해드릴게요.</p>
<hr>
<p>지금 보이는 건 VS Code 안의 <strong>Claude Code 패널</strong>입니다.</p>
<p>역할은:</p>
<ul>
<li>AI에게 코드 수정 요청</li>
<li>터미널 명령 실행</li>
<li>파일 생성/수정</li>
<li>프로젝트 분석</li>
<li>Git 작업 보조</li>
</ul>
<p>같은 걸 하는 AI 코딩 도우미입니다.</p>
<hr>
<p>지금 작은 창처럼 보이는 이유는:</p>
<pre><code class="language-text">Split Editor Right</code></pre>
<p>상태라서 VS Code 내부에 “분할 창”으로 들어가 있기 때문입니다.</p>
<hr>
<h2 id="원하는-것-완전히-바깥-창으로-분리">원하는 것: 완전히 바깥 창으로 분리</h2>
<p>가능합니다.</p>
<p>방법 1 (가장 쉬움)</p>
<h3 id="탭-끌어내기">탭 끌어내기</h3>
<ol>
<li>위의 <code>Claude Code</code> 탭 클릭</li>
<li>마우스로 잡고</li>
<li>VS Code 바깥 화면으로 드래그</li>
</ol>
<p>그러면 새 창으로 분리됩니다.</p>
<hr>
<p>방법 2</p>
<h3 id="우클릭-메뉴">우클릭 메뉴</h3>
<p><code>Claude Code</code> 탭 우클릭 →</p>
<pre><code class="language-text">Move Into New Window</code></pre>
<p>선택</p>
<p>(버전에 따라 메뉴 이름 다를 수 있음)</p>
<hr>
<p>방법 3</p>
<h3 id="새-vs-code-창으로-복제">새 VS Code 창으로 복제</h3>
<pre><code class="language-text">File → New Window</code></pre>
<p>새 창 연 다음
Claude Code를 그 창으로 이동</p>
<hr>
<p>추가 팁:</p>
<p>현재 화면 우측 상단에 있는:</p>
<pre><code class="language-text">Split Editor Right</code></pre>
<p>체크 해제하거나</p>
<pre><code class="language-text">View → Editor Layout → Single</code></pre>
<p>로 바꾸면 분할도 사라집니다.</p>
<hr>
<p>그리고 지금 화면의:</p>
<pre><code class="language-text">Press Shift + Tab to automatically approve code edits</code></pre>
<p>는 Claude가 코드 수정할 때 매번 승인 묻지 않고 자동 적용하는 기능입니다.
실수 방지를 위해 처음엔 자동승인 끄고 쓰는 걸 추천합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[vscode 확장자]]></title>
            <link>https://velog.io/@hy_1023/vscosdeextension</link>
            <guid>https://velog.io/@hy_1023/vscosdeextension</guid>
            <pubDate>Tue, 12 May 2026 14:43:21 GMT</pubDate>
            <description><![CDATA[<p>아래 조합이면 <strong>Windows + VS Code + Ubuntu 24 + GitHub + Python/Django DRF + SQLite + Docker + YAML + 보안 + AWS 배포 + AI/Embedding</strong> 개발에 충분합니다.</p>
<h1 id="1-vs-code-필수-확장">1. VS Code 필수 확장</h1>
<pre><code class="language-bash">code --install-extension ms-ceintl.vscode-language-pack-ko
code --install-extension ms-python.python
code --install-extension ms-python.vscode-pylance
code --install-extension ms-python.black-formatter
code --install-extension charliermarsh.ruff
code --install-extension ms-python.debugpy
code --install-extension ms-toolsai.jupyter

code --install-extension eamodio.gitlens
code --install-extension GitHub.vscode-github-actions
code --install-extension GitHub.vscode-pull-request-github

code --install-extension ms-azuretools.vscode-docker
code --install-extension ms-vscode-remote.remote-ssh
code --install-extension ms-vscode-remote.remote-containers
code --install-extension redhat.vscode-yaml

code --install-extension esbenp.prettier-vscode
code --install-extension usernamehw.errorlens
code --install-extension streetsidesoftware.code-spell-checker
code --install-extension PKief.material-icon-theme

code --install-extension humao.rest-client
code --install-extension rangav.vscode-thunder-client
code --install-extension alexcvzz.vscode-sqlite</code></pre>
<hr>
<h1 id="2-분야별-추천-확장">2. 분야별 추천 확장</h1>
<h2 id="python--django--drf">Python / Django / DRF</h2>
<p>필수:</p>
<pre><code class="language-bash">ms-python.python
ms-python.vscode-pylance
ms-python.black-formatter
charliermarsh.ruff
ms-python.debugpy</code></pre>
<p>추천:</p>
<pre><code class="language-bash">batisteo.vscode-django
njpwerner.autodocstring</code></pre>
<p>설치:</p>
<pre><code class="language-bash">code --install-extension batisteo.vscode-django
code --install-extension njpwerner.autodocstring</code></pre>
<hr>
<h2 id="api-테스트용">API 테스트용</h2>
<p>둘 중 하나만 써도 됩니다.</p>
<pre><code class="language-bash">code --install-extension humao.rest-client
code --install-extension rangav.vscode-thunder-client</code></pre>
<p>추천은 <strong>Thunder Client</strong>입니다.
Postman 대체로 쓰기 좋습니다.</p>
<hr>
<h2 id="sqlite-db-확인">SQLite DB 확인</h2>
<pre><code class="language-bash">code --install-extension alexcvzz.vscode-sqlite</code></pre>
<p>추가 프로그램:</p>
<pre><code class="language-bash">sudo apt install sqlite3</code></pre>
<p>GUI가 필요하면:</p>
<pre><code class="language-bash">sudo apt install sqlitebrowser</code></pre>
<hr>
<h2 id="docker--docker-compose--dev-container">Docker / docker-compose / Dev Container</h2>
<pre><code class="language-bash">code --install-extension ms-azuretools.vscode-docker
code --install-extension ms-vscode-remote.remote-containers</code></pre>
<hr>
<h2 id="yaml">YAML</h2>
<pre><code class="language-bash">code --install-extension redhat.vscode-yaml</code></pre>
<p>Docker Compose, GitHub Actions, AWS 설정 파일 볼 때 필수입니다.</p>
<hr>
<h2 id="git--github">Git / GitHub</h2>
<pre><code class="language-bash">code --install-extension eamodio.gitlens
code --install-extension GitHub.vscode-pull-request-github
code --install-extension GitHub.vscode-github-actions</code></pre>
<hr>
<h2 id="ai--embedding-개발">AI / Embedding 개발</h2>
<pre><code class="language-bash">code --install-extension ms-toolsai.jupyter</code></pre>
<p>Python 패키지 추천:</p>
<pre><code class="language-bash">pip install \
numpy pandas scikit-learn matplotlib \
jupyterlab \
openai \
langchain langchain-community \
chromadb \
sentence-transformers \
faiss-cpu</code></pre>
<p>간단히 말하면:</p>
<table>
<thead>
<tr>
<th>목적</th>
<th>추천</th>
</tr>
</thead>
<tbody><tr>
<td>OpenAI API 사용</td>
<td><code>openai</code></td>
</tr>
<tr>
<td>RAG / AI 체인</td>
<td><code>langchain</code></td>
</tr>
<tr>
<td>로컬 벡터DB</td>
<td><code>chromadb</code></td>
</tr>
<tr>
<td>임베딩 모델</td>
<td><code>sentence-transformers</code></td>
</tr>
<tr>
<td>빠른 벡터 검색</td>
<td><code>faiss-cpu</code></td>
</tr>
</tbody></table>
<hr>
<h1 id="3-ubuntu-24-필수-프로그램">3. Ubuntu 24 필수 프로그램</h1>
<pre><code class="language-bash">sudo apt update &amp;&amp; sudo apt upgrade -y

sudo apt install -y \
git curl wget unzip zip \
python3 python3-pip python3-venv \
build-essential gcc g++ make \
sqlite3 sqlitebrowser \
docker.io docker-compose-v2 \
openssh-client \
tree htop \
shellcheck</code></pre>
<p>Docker 권한:</p>
<pre><code class="language-bash">sudo usermod -aG docker $USER
newgrp docker</code></pre>
<p>확인:</p>
<pre><code class="language-bash">docker --version
docker compose version</code></pre>
<hr>
<h1 id="4-windows-쪽-필수-프로그램">4. Windows 쪽 필수 프로그램</h1>
<p>Windows에서 같이 설치 추천:</p>
<ol>
<li><strong>VS Code</strong></li>
<li><strong>Git for Windows</strong></li>
<li><strong>Docker Desktop</strong></li>
<li><strong>Python 3.12 이상</strong></li>
<li><strong>Windows Terminal</strong></li>
<li><strong>WSL2 + Ubuntu 24.04</strong></li>
<li><strong>DB Browser for SQLite</strong></li>
<li><strong>Postman 또는 Thunder Client</strong></li>
<li><strong>AWS CLI</strong></li>
<li><strong>GitHub Desktop</strong> 선택</li>
</ol>
<p>WSL 설치:</p>
<pre><code class="language-powershell">wsl --install -d Ubuntu-24.04</code></pre>
<hr>
<h1 id="5-django-drf-기본-패키지">5. Django DRF 기본 패키지</h1>
<p>가상환경 생성:</p>
<pre><code class="language-bash">python3 -m venv venv
source venv/bin/activate</code></pre>
<p>설치:</p>
<pre><code class="language-bash">pip install \
django \
djangorestframework \
django-cors-headers \
python-dotenv \
drf-spectacular \
gunicorn \
whitenoise</code></pre>
<p>개발용 추가:</p>
<pre><code class="language-bash">pip install \
black \
ruff \
pytest \
pytest-django \
coverage</code></pre>
<p>AI 추가:</p>
<pre><code class="language-bash">pip install \
openai \
langchain \
chromadb \
sentence-transformers \
faiss-cpu</code></pre>
<hr>
<h1 id="6-django-drf-추천-구조">6. Django DRF 추천 구조</h1>
<pre><code class="language-txt">project/
├── config/
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── apps/
│   ├── users/
│   ├── api/
│   └── ai/
├── db.sqlite3
├── manage.py
├── requirements.txt
├── Dockerfile
├── docker-compose.yml
├── .env
└── .gitignore</code></pre>
<hr>
<h1 id="7-serializer-필수-개념">7. Serializer 필수 개념</h1>
<p>DRF에서 Serializer는 Django 모델과 JSON 사이를 변환합니다.</p>
<pre><code class="language-python">from rest_framework import serializers
from .models import Post

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = &quot;__all__&quot;</code></pre>
<p>APIView 예시:</p>
<pre><code class="language-python">from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Post
from .serializers import PostSerializer

class PostListAPIView(APIView):
    def get(self, request):
        posts = Post.objects.all()
        serializer = PostSerializer(posts, many=True)
        return Response(serializer.data)</code></pre>
<hr>
<h1 id="8-dockerfile-예시">8. Dockerfile 예시</h1>
<pre><code class="language-dockerfile">FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD [&quot;gunicorn&quot;, &quot;config.wsgi:application&quot;, &quot;--bind&quot;, &quot;0.0.0.0:8000&quot;]</code></pre>
<hr>
<h1 id="9-docker-composeyml-예시">9. docker-compose.yml 예시</h1>
<p>SQLite 기준:</p>
<pre><code class="language-yaml">services:
  web:
    build: .
    container_name: django_drf_app
    ports:
      - &quot;8000:8000&quot;
    volumes:
      - .:/app
    env_file:
      - .env
    command: python manage.py runserver 0.0.0.0:8000</code></pre>
<p>실행:</p>
<pre><code class="language-bash">docker compose up --build</code></pre>
<hr>
<h1 id="10-env-예시">10. .env 예시</h1>
<pre><code class="language-env">SECRET_KEY=your-secret-key
DEBUG=True
ALLOWED_HOSTS=127.0.0.1,localhost

OPENAI_API_KEY=your-openai-api-key</code></pre>
<hr>
<h1 id="11-gitignore-필수">11. .gitignore 필수</h1>
<pre><code class="language-gitignore">venv/
__pycache__/
*.pyc
.env
db.sqlite3
staticfiles/
media/
.vscode/</code></pre>
<p>단, 팀 설정을 공유하려면 <code>.vscode/settings.json</code>은 포함해도 됩니다.</p>
<hr>
<h1 id="12-보안-필수-체크">12. 보안 필수 체크</h1>
<p>Django 배포 전 필수:</p>
<pre><code class="language-python">DEBUG = False
ALLOWED_HOSTS = [&quot;your-domain.com&quot;, &quot;your-aws-ip&quot;]</code></pre>
<p>추가 보안 설정:</p>
<pre><code class="language-python">CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True</code></pre>
<p>비밀값은 절대 GitHub에 올리지 마세요.</p>
<pre><code class="language-txt">.env
SECRET_KEY
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
OPENAI_API_KEY</code></pre>
<hr>
<h1 id="13-aws-배포-추천-순서">13. AWS 배포 추천 순서</h1>
<p>초보자 기준 추천:</p>
<h2 id="1순위-aws-lightsail">1순위: AWS Lightsail</h2>
<p>가장 쉬움. Django + Docker 배포에 적합.</p>
<h2 id="2순위-ec2">2순위: EC2</h2>
<p>실무형. Ubuntu 서버에 Docker로 직접 배포.</p>
<h2 id="3순위-elastic-beanstalk">3순위: Elastic Beanstalk</h2>
<p>AWS 관리형 배포.</p>
<p>처음이면 <strong>Lightsail 또는 EC2 + Docker</strong> 추천합니다.</p>
<hr>
<h1 id="14-aws-배포에-필요한-프로그램">14. AWS 배포에 필요한 프로그램</h1>
<p>Ubuntu / Windows 공통:</p>
<pre><code class="language-bash">aws --version
ssh -V
git --version
docker --version</code></pre>
<p>AWS CLI 설치 후:</p>
<pre><code class="language-bash">aws configure</code></pre>
<p>필요한 것:</p>
<pre><code class="language-txt">AWS 계정
EC2 또는 Lightsail 인스턴스
SSH 키 파일
도메인 선택사항
보안그룹 22, 80, 443, 8000
Docker
Nginx
Gunicorn</code></pre>
<hr>
<h1 id="15-최종-추천-조합">15. 최종 추천 조합</h1>
<table>
<thead>
<tr>
<th>목적</th>
<th>추천</th>
</tr>
</thead>
<tbody><tr>
<td>OS</td>
<td>Windows + WSL2 Ubuntu 24.04</td>
</tr>
<tr>
<td>에디터</td>
<td>VS Code</td>
</tr>
<tr>
<td>언어</td>
<td>Python 3.12</td>
</tr>
<tr>
<td>백엔드</td>
<td>Django + DRF</td>
</tr>
<tr>
<td>DB</td>
<td>개발 SQLite, 운영 PostgreSQL 추천</td>
</tr>
<tr>
<td>API 문서</td>
<td>drf-spectacular</td>
</tr>
<tr>
<td>AI</td>
<td>OpenAI API + LangChain</td>
</tr>
<tr>
<td>Embedding DB</td>
<td>ChromaDB 또는 FAISS</td>
</tr>
<tr>
<td>컨테이너</td>
<td>Docker Compose</td>
</tr>
<tr>
<td>배포</td>
<td>AWS Lightsail 또는 EC2</td>
</tr>
<tr>
<td>웹서버</td>
<td>Nginx</td>
</tr>
<tr>
<td>앱서버</td>
<td>Gunicorn</td>
</tr>
<tr>
<td>보안</td>
<td><code>.env</code>, HTTPS, DEBUG=False</td>
</tr>
</tbody></table>
<hr>
<h1 id="16-제일-먼저-설치할-것만-요약">16. 제일 먼저 설치할 것만 요약</h1>
<pre><code class="language-bash">code --install-extension ms-python.python
code --install-extension ms-python.vscode-pylance
code --install-extension charliermarsh.ruff
code --install-extension ms-python.black-formatter
code --install-extension ms-azuretools.vscode-docker
code --install-extension redhat.vscode-yaml
code --install-extension eamodio.gitlens
code --install-extension GitHub.vscode-pull-request-github
code --install-extension batisteo.vscode-django
code --install-extension humao.rest-client
code --install-extension alexcvzz.vscode-sqlite</code></pre>
<p>이 세팅이면 <strong>Django DRF + Serializer + SQLite + AI Embedding + Docker + AWS 배포</strong>까지 한 환경에서 개발 가능합니다.</p>
<hr>
<h1 id="ubuntu-24--vs-code-개발환경-풀세팅-가이드">Ubuntu 24 + VS Code 개발환경 풀세팅 가이드</h1>
<p>실무 기준으로 바로 개발 가능한 수준으로 정리했습니다.</p>
<hr>
<h1 id="1-공통-기본-설치">1. 공통 기본 설치</h1>
<h2 id="시스템-업데이트">시스템 업데이트</h2>
<pre><code class="language-bash">sudo apt update &amp;&amp; sudo apt upgrade -y</code></pre>
<hr>
<h2 id="기본-개발-패키지">기본 개발 패키지</h2>
<pre><code class="language-bash">sudo apt install -y \
git curl wget unzip zip \
build-essential gcc g++ make cmake \
software-properties-common apt-transport-https \
python3 python3-pip python3-venv \
openjdk-21-jdk \
gdb pkg-config \
net-tools htop tree \
shellcheck</code></pre>
<hr>
<h1 id="2-vs-code-설치">2. VS Code 설치</h1>
<h2 id="microsoft-공식-저장소-방식-추천">Microsoft 공식 저장소 방식 추천</h2>
<pre><code class="language-bash">wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor &gt; packages.microsoft.gpg

sudo install -D -o root -g root -m 644 packages.microsoft.gpg \
/etc/apt/keyrings/packages.microsoft.gpg

echo &quot;deb [arch=amd64 signed-by=/etc/apt/keyrings/packages.microsoft.gpg] \
https://packages.microsoft.com/repos/code stable main&quot; | \
sudo tee /etc/apt/sources.list.d/vscode.list

sudo apt update
sudo apt install code</code></pre>
<hr>
<h1 id="3-vs-code-공통-확장-설치">3. VS Code 공통 확장 설치</h1>
<pre><code class="language-bash">code --install-extension ms-ceintl.vscode-language-pack-ko
code --install-extension usernamehw.errorlens
code --install-extension eamodio.gitlens
code --install-extension esbenp.prettier-vscode
code --install-extension EditorConfig.EditorConfig
code --install-extension christian-kohler.path-intellisense
code --install-extension PKief.material-icon-theme
code --install-extension streetsidesoftware.code-spell-checker
code --install-extension wayou.vscode-todo-highlight</code></pre>
<hr>
<h1 id="4-웹개발용-vscode-풀세팅">4. 웹개발용 VSCode 풀세팅</h1>
<h1 id="nodejs-설치-lts">Node.js 설치 (LTS)</h1>
<pre><code class="language-bash">curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs</code></pre>
<p>확인:</p>
<pre><code class="language-bash">node -v
npm -v</code></pre>
<hr>
<h1 id="웹개발-추천-확장">웹개발 추천 확장</h1>
<pre><code class="language-bash">code --install-extension dbaeumer.vscode-eslint
code --install-extension bradlc.vscode-tailwindcss
code --install-extension christian-kohler.npm-intellisense
code --install-extension formulahendry.auto-rename-tag
code --install-extension formulahendry.auto-close-tag
code --install-extension ritwickdey.LiveServer</code></pre>
<hr>
<h1 id="react-프로젝트-생성">React 프로젝트 생성</h1>
<pre><code class="language-bash">npm create vite@latest myapp
cd myapp
npm install
npm run dev</code></pre>
<hr>
<h1 id="추천-settingsjson">추천 settings.json</h1>
<pre><code class="language-json">{
  &quot;editor.formatOnSave&quot;: true,
  &quot;editor.defaultFormatter&quot;: &quot;esbenp.prettier-vscode&quot;,
  &quot;eslint.validate&quot;: [&quot;javascript&quot;, &quot;typescript&quot;],
  &quot;files.autoSave&quot;: &quot;afterDelay&quot;
}</code></pre>
<hr>
<h1 id="5-python-ai-개발용-세팅">5. Python AI 개발용 세팅</h1>
<h1 id="python-확장">Python 확장</h1>
<pre><code class="language-bash">code --install-extension ms-python.python
code --install-extension ms-python.vscode-pylance
code --install-extension ms-toolsai.jupyter</code></pre>
<hr>
<h1 id="aiml-라이브러리">AI/ML 라이브러리</h1>
<pre><code class="language-bash">pip install \
numpy pandas matplotlib seaborn \
scikit-learn jupyterlab \
torch torchvision torchaudio \
transformers datasets</code></pre>
<hr>
<h1 id="가상환경-추천">가상환경 추천</h1>
<pre><code class="language-bash">python3 -m venv venv
source venv/bin/activate</code></pre>
<hr>
<h1 id="jupyter-실행">Jupyter 실행</h1>
<pre><code class="language-bash">jupyter lab</code></pre>
<hr>
<h1 id="cuda-확인-nvidia">CUDA 확인 (NVIDIA)</h1>
<pre><code class="language-bash">nvidia-smi</code></pre>
<p>PyTorch GPU 확인:</p>
<pre><code class="language-python">import torch
print(torch.cuda.is_available())</code></pre>
<hr>
<h1 id="6-ubuntu-24--docker-개발환경">6. Ubuntu 24 + Docker 개발환경</h1>
<h1 id="docker-설치">Docker 설치</h1>
<pre><code class="language-bash">curl -fsSL https://get.docker.com | sudo sh</code></pre>
<hr>
<h1 id="현재-사용자-docker-권한-추가">현재 사용자 docker 권한 추가</h1>
<pre><code class="language-bash">sudo usermod -aG docker $USER
newgrp docker</code></pre>
<hr>
<h1 id="docker-compose">Docker Compose</h1>
<p>Ubuntu 24는 기본 포함됨:</p>
<pre><code class="language-bash">docker compose version</code></pre>
<hr>
<h1 id="vs-code-docker-확장">VS Code Docker 확장</h1>
<pre><code class="language-bash">code --install-extension ms-azuretools.vscode-docker
code --install-extension ms-vscode-remote.remote-containers</code></pre>
<hr>
<h1 id="테스트">테스트</h1>
<pre><code class="language-bash">docker run hello-world</code></pre>
<hr>
<h1 id="개발용-docker-composeyml-예시">개발용 docker-compose.yml 예시</h1>
<pre><code class="language-yaml">services:
  app:
    image: node:22
    working_dir: /app
    volumes:
      - .:/app
    command: bash</code></pre>
<hr>
<h1 id="7-cc-개발환경">7. C/C++ 개발환경</h1>
<h1 id="필수-패키지">필수 패키지</h1>
<pre><code class="language-bash">sudo apt install build-essential gdb cmake</code></pre>
<hr>
<h1 id="vs-code-확장">VS Code 확장</h1>
<pre><code class="language-bash">code --install-extension ms-vscode.cpptools
code --install-extension ms-vscode.cmake-tools</code></pre>
<hr>
<h1 id="테스트-코드">테스트 코드</h1>
<pre><code class="language-cpp">#include &lt;iostream&gt;

int main() {
    std::cout &lt;&lt; &quot;Hello Ubuntu 24&quot; &lt;&lt; std::endl;
}</code></pre>
<p>빌드:</p>
<pre><code class="language-bash">g++ main.cpp -o app
./app</code></pre>
<hr>
<h1 id="8-spring-boot-개발환경">8. Spring Boot 개발환경</h1>
<h1 id="java-설치-확인">Java 설치 확인</h1>
<pre><code class="language-bash">java -version
javac -version</code></pre>
<hr>
<h1 id="vs-code-java-확장">VS Code Java 확장</h1>
<pre><code class="language-bash">code --install-extension vscjava.vscode-java-pack
code --install-extension vmware.vscode-spring-boot</code></pre>
<hr>
<h1 id="gradle-설치">Gradle 설치</h1>
<pre><code class="language-bash">sudo apt install gradle</code></pre>
<hr>
<h1 id="spring-boot-프로젝트-생성">Spring Boot 프로젝트 생성</h1>
<pre><code class="language-bash">curl https://start.spring.io/starter.zip \
-d dependencies=web,data-jpa,lombok \
-d type=gradle-project \
-o demo.zip

unzip demo.zip
cd demo</code></pre>
<p>실행:</p>
<pre><code class="language-bash">./gradlew bootRun</code></pre>
<hr>
<h1 id="9-flutter-개발환경">9. Flutter 개발환경</h1>
<h1 id="flutter-sdk-설치">Flutter SDK 설치</h1>
<pre><code class="language-bash">cd ~

git clone https://github.com/flutter/flutter.git</code></pre>
<hr>
<h1 id="path-추가">PATH 추가</h1>
<pre><code class="language-bash">echo &#39;export PATH=&quot;$PATH:$HOME/flutter/bin&quot;&#39; &gt;&gt; ~/.bashrc
source ~/.bashrc</code></pre>
<hr>
<h1 id="flutter-진단">Flutter 진단</h1>
<pre><code class="language-bash">flutter doctor</code></pre>
<hr>
<h1 id="android-studio-설치-추천">Android Studio 설치 추천</h1>
<pre><code class="language-bash">sudo snap install android-studio --classic</code></pre>
<hr>
<h1 id="flutter-vs-code-확장">Flutter VS Code 확장</h1>
<pre><code class="language-bash">code --install-extension Dart-Code.flutter
code --install-extension Dart-Code.dart-code</code></pre>
<hr>
<h1 id="앱-생성">앱 생성</h1>
<pre><code class="language-bash">flutter create myapp
cd myapp
flutter run</code></pre>
<hr>
<h1 id="10-vscode-성능-최적화-설정">10. VSCode 성능 최적화 설정</h1>
<h1 id="settingsjson-추천">settings.json 추천</h1>
<pre><code class="language-json">{
  &quot;editor.minimap.enabled&quot;: false,
  &quot;editor.semanticHighlighting.enabled&quot;: false,
  &quot;breadcrumbs.enabled&quot;: false,
  &quot;files.autoSave&quot;: &quot;afterDelay&quot;,
  &quot;files.exclude&quot;: {
    &quot;**/.git&quot;: true,
    &quot;**/node_modules&quot;: true,
    &quot;**/.cache&quot;: true
  },
  &quot;search.followSymlinks&quot;: false,
  &quot;git.autofetch&quot;: true,
  &quot;extensions.autoUpdate&quot;: false,
  &quot;telemetry.telemetryLevel&quot;: &quot;off&quot;,
  &quot;workbench.startupEditor&quot;: &quot;none&quot;
}</code></pre>
<hr>
<h1 id="11-개발자용-터미널-추천">11. 개발자용 터미널 추천</h1>
<h2 id="zsh--oh-my-zsh">zsh + oh-my-zsh</h2>
<pre><code class="language-bash">sudo apt install zsh

sh -c &quot;$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)&quot;</code></pre>
<hr>
<h1 id="추천-플러그인">추천 플러그인</h1>
<p><code>.zshrc</code></p>
<pre><code class="language-bash">plugins=(git docker npm python)</code></pre>
<hr>
<h1 id="12-git-기본-설정">12. Git 기본 설정</h1>
<pre><code class="language-bash">git config --global user.name &quot;YOUR_NAME&quot;
git config --global user.email &quot;YOUR_EMAIL&quot;</code></pre>
<hr>
<h1 id="13-실무-추천-추가-도구">13. 실무 추천 추가 도구</h1>
<h2 id="lazygit">LazyGit</h2>
<pre><code class="language-bash">sudo add-apt-repository ppa:lazygit-team/release
sudo apt update
sudo apt install lazygit</code></pre>
<hr>
<h2 id="fzf">fzf</h2>
<pre><code class="language-bash">sudo apt install fzf</code></pre>
<hr>
<h1 id="14-개인적으로-추천하는-조합">14. 개인적으로 추천하는 조합</h1>
<h2 id="웹개발">웹개발</h2>
<ul>
<li>React + Vite</li>
<li>Node LTS</li>
<li>Docker</li>
<li>TailwindCSS</li>
</ul>
<hr>
<h2 id="ai-개발">AI 개발</h2>
<ul>
<li>Python venv</li>
<li>JupyterLab</li>
<li>PyTorch</li>
<li>VSCode Jupyter</li>
</ul>
<hr>
<h2 id="백엔드">백엔드</h2>
<ul>
<li>Spring Boot + Docker + PostgreSQL</li>
</ul>
<hr>
<h1 id="15-ubuntu-24에서-특히-주의할-점">15. Ubuntu 24에서 특히 주의할 점</h1>
<h2 id="snap-vscode보다-deb-설치-추천">Snap VSCode보다 deb 설치 추천</h2>
<p>snap 버전은:</p>
<ul>
<li>느림</li>
<li>권한 이슈</li>
<li>Docker 연동 문제</li>
</ul>
<p>→ 위 공식 저장소 방식 추천.</p>
<hr>
<h2 id="wayland-문제">Wayland 문제</h2>
<p>터미널/Flutter 이슈 있으면:</p>
<pre><code class="language-bash">code --disable-gpu</code></pre>
<p>또는 로그인 시:</p>
<ul>
<li>Ubuntu on Xorg 선택</li>
</ul>
<hr>
<p>원하면 다음 단계로:</p>
<ul>
<li>React + Spring Boot + Docker 풀스택 세팅</li>
<li>NVIDIA CUDA + PyTorch GPU 세팅</li>
<li>Kubernetes 개발환경</li>
<li>WSL 대신 Ubuntu 단독 개발환경 최적화</li>
<li>Neovim + VSCode 하이브리드 세팅</li>
<li>실무용 dotfiles</li>
<li>GitHub Actions CI/CD</li>
<li>PostgreSQL/MySQL 로컬 개발환경</li>
</ul>
<p>까지 이어서 정리해드릴 수 있습니다.</p>
<hr>
<p>Ubuntu 24에서 VS Code를 사용할 때 기본으로 많이 설치하는 확장 프로그램들을 용도별로 정리해드릴게요.
개발 언어별 + 공통 생산성 기준으로 추천합니다.</p>
<hr>
<h1 id="1-필수-공통-확장">1. 필수 공통 확장</h1>
<h2 id="✅-korean-language-pack">✅ Korean Language Pack</h2>
<ul>
<li><code>MS-CEINTL.vscode-language-pack-ko</code></li>
<li>VS Code 한글화</li>
</ul>
<hr>
<h2 id="✅-error-lens">✅ Error Lens</h2>
<ul>
<li><code>usernamehw.errorlens</code></li>
<li>에러/경고를 코드 줄에 바로 표시</li>
<li>생산성 체감 큼</li>
</ul>
<hr>
<h2 id="✅-gitlens">✅ GitLens</h2>
<ul>
<li><code>eamodio.gitlens</code></li>
<li>Git blame / 히스토리 강화</li>
<li>협업 시 거의 필수</li>
</ul>
<hr>
<h2 id="✅-prettier">✅ Prettier</h2>
<ul>
<li><code>esbenp.prettier-vscode</code></li>
<li>코드 자동 포맷팅</li>
</ul>
<p>설정 추천:</p>
<pre><code class="language-json">&quot;editor.formatOnSave&quot;: true</code></pre>
<hr>
<h2 id="✅-editorconfig">✅ EditorConfig</h2>
<ul>
<li><code>EditorConfig.EditorConfig</code></li>
<li>팀 프로젝트 줄바꿈/들여쓰기 통일</li>
</ul>
<hr>
<h2 id="✅-path-intellisense">✅ Path Intellisense</h2>
<ul>
<li><code>christian-kohler.path-intellisense</code></li>
<li>파일 경로 자동완성</li>
</ul>
<hr>
<h2 id="✅-material-icon-theme">✅ Material Icon Theme</h2>
<ul>
<li><code>PKief.material-icon-theme</code></li>
<li>파일 아이콘 개선</li>
</ul>
<hr>
<h1 id="2-개발-언어별-추천">2. 개발 언어별 추천</h1>
<h1 id="python-개발">Python 개발</h1>
<h2 id="✅-python">✅ Python</h2>
<ul>
<li><code>ms-python.python</code></li>
</ul>
<h2 id="✅-pylance">✅ Pylance</h2>
<ul>
<li><code>ms-python.vscode-pylance</code></li>
</ul>
<h2 id="✅-jupyter">✅ Jupyter</h2>
<ul>
<li><code>ms-toolsai.jupyter</code></li>
</ul>
<p>Ubuntu 24에서는 추가 패키지도 추천:</p>
<pre><code class="language-bash">sudo apt install python3-venv python3-pip</code></pre>
<hr>
<h1 id="nodejs--react--typescript">Node.js / React / TypeScript</h1>
<h2 id="✅-eslint">✅ ESLint</h2>
<ul>
<li><code>dbaeumer.vscode-eslint</code></li>
</ul>
<h2 id="✅-npm-intellisense">✅ npm Intellisense</h2>
<ul>
<li><code>christian-kohler.npm-intellisense</code></li>
</ul>
<h2 id="✅-tailwind-css-intellisense">✅ Tailwind CSS IntelliSense</h2>
<ul>
<li><code>bradlc.vscode-tailwindcss</code></li>
</ul>
<hr>
<h1 id="java-개발">Java 개발</h1>
<h2 id="✅-extension-pack-for-java">✅ Extension Pack for Java</h2>
<ul>
<li><code>vscjava.vscode-java-pack</code></li>
</ul>
<p>추가 설치:</p>
<pre><code class="language-bash">sudo apt install openjdk-21-jdk</code></pre>
<p>Ubuntu 24 기준 JDK 21 추천.</p>
<hr>
<h1 id="cc">C/C++</h1>
<h2 id="✅-cc">✅ C/C++</h2>
<ul>
<li><code>ms-vscode.cpptools</code></li>
</ul>
<p>Ubuntu 패키지:</p>
<pre><code class="language-bash">sudo apt install build-essential gdb</code></pre>
<hr>
<h1 id="docker--devops">Docker / DevOps</h1>
<h2 id="✅-docker">✅ Docker</h2>
<ul>
<li><code>ms-azuretools.vscode-docker</code></li>
</ul>
<h2 id="✅-remote---ssh">✅ Remote - SSH</h2>
<ul>
<li><code>ms-vscode-remote.remote-ssh</code></li>
</ul>
<h2 id="✅-dev-containers">✅ Dev Containers</h2>
<ul>
<li><code>ms-vscode-remote.remote-containers</code></li>
</ul>
<hr>
<h1 id="3-ubuntu-환경에서-특히-추천">3. Ubuntu 환경에서 특히 추천</h1>
<h2 id="✅-shellcheck">✅ ShellCheck</h2>
<ul>
<li><code>timonwong.shellcheck</code></li>
<li>bash 스크립트 검사</li>
</ul>
<p>설치:</p>
<pre><code class="language-bash">sudo apt install shellcheck</code></pre>
<hr>
<h2 id="✅-yaml">✅ YAML</h2>
<ul>
<li><code>redhat.vscode-yaml</code></li>
</ul>
<p>Kubernetes/Docker Compose 작업 시 필수급.</p>
<hr>
<h2 id="✅-markdown-all-in-one">✅ Markdown All in One</h2>
<ul>
<li><code>yzhang.markdown-all-in-one</code></li>
</ul>
<p>README 작성 편해짐.</p>
<hr>
<h1 id="4-개인적으로-강력-추천">4. 개인적으로 강력 추천</h1>
<h2 id="✅-code-spell-checker">✅ Code Spell Checker</h2>
<ul>
<li><code>streetsidesoftware.code-spell-checker</code></li>
</ul>
<p>주석/변수명 오타 방지.</p>
<hr>
<h2 id="✅-todo-highlight">✅ TODO Highlight</h2>
<ul>
<li><code>wayou.vscode-todo-highlight</code></li>
</ul>
<p>TODO/FIXME 강조.</p>
<hr>
<h1 id="5-설치-한번에-하기">5. 설치 한번에 하기</h1>
<p>터미널에서:</p>
<pre><code class="language-bash">code --install-extension ms-ceintl.vscode-language-pack-ko
code --install-extension usernamehw.errorlens
code --install-extension eamodio.gitlens
code --install-extension esbenp.prettier-vscode
code --install-extension EditorConfig.EditorConfig
code --install-extension christian-kohler.path-intellisense
code --install-extension PKief.material-icon-theme</code></pre>
<hr>
<h1 id="6-ubuntu-24에서-같이-설치하면-좋은-패키지">6. Ubuntu 24에서 같이 설치하면 좋은 패키지</h1>
<pre><code class="language-bash">sudo apt update

sudo apt install \
git \
curl \
wget \
build-essential \
gdb \
python3-pip \
python3-venv \
openjdk-21-jdk \
shellcheck</code></pre>
<hr>
<h1 id="7-추천-vs-code-설정-settingsjson">7. 추천 VS Code 설정 (<code>settings.json</code>)</h1>
<pre><code class="language-json">{
  &quot;editor.fontSize&quot;: 14,
  &quot;editor.tabSize&quot;: 2,
  &quot;editor.formatOnSave&quot;: true,
  &quot;files.autoSave&quot;: &quot;afterDelay&quot;,
  &quot;terminal.integrated.defaultProfile.linux&quot;: &quot;bash&quot;,
  &quot;editor.minimap.enabled&quot;: false
}</code></pre>
<hr>
<p>원하면 추가로:</p>
<ul>
<li>웹개발용 VSCode 풀세팅</li>
<li>Python AI 개발용 세팅</li>
<li>Ubuntu 24 + Docker 개발환경</li>
<li>C/C++ 개발환경</li>
<li>Spring Boot 개발환경</li>
<li>Flutter 개발환경</li>
<li>VSCode 성능 최적화 설정</li>
</ul>
<p>까지 한 번에 정리해드릴 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[20260421_]]></title>
            <link>https://velog.io/@hy_1023/20260421</link>
            <guid>https://velog.io/@hy_1023/20260421</guid>
            <pubDate>Tue, 21 Apr 2026 02:16:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hy_1023/post/c151c89b-484a-41b8-aeed-84e2a276e978/image.png" alt=""></p>
<p>템플릿에 베이스 푸터 헤더 나누는 이유가  나중에 다른 api 와 겹치지않도록 나누는것이고 </p>
<p>런서버를 켜놓고 수정이 가능하다 ,  </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[20260420_프로젝트 막힌부분 ]]></title>
            <link>https://velog.io/@hy_1023/20260420%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%89%ED%9E%8C%EB%B6%80%EB%B6%84</link>
            <guid>https://velog.io/@hy_1023/20260420%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%89%ED%9E%8C%EB%B6%80%EB%B6%84</guid>
            <pubDate>Mon, 20 Apr 2026 05:51:27 GMT</pubDate>
            <description><![CDATA[<p>API 사용할때  문서먼저 확인해보고 그들이 필수요건이 무엇인지  필요없는것은 무엇인지확인한다음 </p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/3877d924-d7df-4cc0-a2ca-ed5e568b221a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/b540c8e4-94bd-4ebc-9682-656a58fb5133/image.png" alt=""></p>
<pre><code>import os
import time
import requests

from django.core.management.base import BaseCommand
from django.db import transaction
from dotenv import load_dotenv

from brokers.models import RealEstateAgent


load_dotenv()


class Command(BaseCommand):
    help = &quot;VWorld 부동산중개업 데이터를 가져와 DB에 저장합니다.&quot;

    def add_arguments(self, parser):
        parser.add_argument(
            &quot;--sigungu&quot;,
            type=str,
            required=False,
            help=&quot;예: 강남구, 관악구, 서초구&quot;
        )
        parser.add_argument(
            &quot;--page&quot;,
            type=int,
            default=1,
            help=&quot;가져올 페이지 번호&quot;
        )
        parser.add_argument(
            &quot;--size&quot;,
            type=int,
            default=10,
            help=&quot;한 번에 가져올 개수&quot;
        )

    def handle(self, *args, **options):
        api_key = os.getenv(&quot;VWORLD_API_KEY&quot;)
        domain = os.getenv(&quot;VWORLD_DOMAIN&quot;)

        if not api_key:
            self.stdout.write(self.style.ERROR(&quot;VWORLD_API_KEY가 .env에 없습니다.&quot;))
            return

        if not domain:
            self.stdout.write(self.style.WARNING(&quot;VWORLD_DOMAIN이 없어 기본값(http://localhost:8000)을 사용합니다.&quot;))
            domain = &quot;http://localhost:8000&quot;

        sigungu = options.get(&quot;sigungu&quot;)
        page = options.get(&quot;page&quot;)
        size = options.get(&quot;size&quot;)

        self.stdout.write(f&quot;api_key exists: {bool(api_key)}&quot;)
        self.stdout.write(f&quot;domain: {domain}&quot;)
        self.stdout.write(f&quot;sigungu: {sigungu}&quot;)
        self.stdout.write(f&quot;page: {page}, size: {size}&quot;)

        url = &quot;https://api.vworld.kr/req/data&quot;

        params = {
            &quot;service&quot;: &quot;data&quot;,
            &quot;request&quot;: &quot;GetFeature&quot;,
            &quot;data&quot;: &quot;LP_PA_CBND_BUBUN&quot;,
            &quot;key&quot;: api_key,
            &quot;domain&quot;: domain,
            &quot;format&quot;: &quot;json&quot;,
            &quot;geometry&quot;: &quot;false&quot;,
            &quot;size&quot;: size,
            &quot;page&quot;: page,
            &quot;geomFilter&quot;: &quot;BOX(127.027,37.497,127.037,37.507)&quot;,
        }

        # 인증키부터 먼저 확인하려면 attrFilter는 잠시 주석 처리해도 됩니다.
        # 아래 필드명 sigungu 는 실제 VWorld 응답 속성명과 다를 수 있습니다.
        # if sigungu:
            # params[&quot;attrFilter&quot;] = f&quot;sigungu:like:{sigungu}&quot;

        self.stdout.write(self.style.WARNING(f&quot;요청 파라미터: {params}&quot;))

        try:
            response = requests.get(url, params=params, timeout=20)
            response.raise_for_status()
            data = response.json()
        except requests.RequestException as e:
            self.stdout.write(self.style.ERROR(f&quot;API 요청 실패: {e}&quot;))
            return
        except ValueError:
            self.stdout.write(self.style.ERROR(&quot;JSON 파싱 실패&quot;))
            return

        self.stdout.write(self.style.SUCCESS(&quot;API 응답 수신 성공&quot;))
        self.stdout.write(str(data)[:3000])

        response_body = data.get(&quot;response&quot;, {})
        status = response_body.get(&quot;status&quot;)

        if status == &quot;ERROR&quot;:
            error_info = response_body.get(&quot;error&quot;, {})
            self.stdout.write(self.style.ERROR(f&quot;VWorld 오류: {error_info}&quot;))
            return

        features = (
            response_body.get(&quot;result&quot;, {})
            .get(&quot;featureCollection&quot;, {})
            .get(&quot;features&quot;, [])
        )

        if not features:
            self.stdout.write(self.style.WARNING(&quot;저장할 데이터가 없습니다.&quot;))
            return

        created_count = 0
        updated_count = 0
        skipped_count = 0

        with transaction.atomic():
            for feature in features:
                props = feature.get(&quot;properties&quot;, {})

                # -----------------------------
                # VWorld 응답 필드명 후보들
                # 실제 응답 보고 필요시 수정하세요.
                # -----------------------------
                office_name = (
                    props.get(&quot;bsnm&quot;)
                    or props.get(&quot;office_name&quot;)
                    or props.get(&quot;BSNM&quot;)
                    or &quot;&quot;
                )

                broker_name = (
                    props.get(&quot;rprsntvNm&quot;)
                    or props.get(&quot;broker_name&quot;)
                    or props.get(&quot;RPRSNTVNM&quot;)
                    or &quot;&quot;
                )

                road_addr = (
                    props.get(&quot;rdnmadr&quot;)
                    or props.get(&quot;road_addr&quot;)
                    or props.get(&quot;RDNMADR&quot;)
                    or &quot;&quot;
                )

                jibun_addr = (
                    props.get(&quot;lnmadr&quot;)
                    or props.get(&quot;jibun_addr&quot;)
                    or props.get(&quot;LNMADR&quot;)
                    or &quot;&quot;
                )

                tel = (
                    props.get(&quot;telno&quot;)
                    or props.get(&quot;phone&quot;)
                    or props.get(&quot;TELNO&quot;)
                    or &quot;&quot;
                )

                sigungu_name = (
                    props.get(&quot;sigungu&quot;)
                    or props.get(&quot;SIGUNGU&quot;)
                    or &quot;&quot;
                )

                license_no = (
                    props.get(&quot;regno&quot;)
                    or props.get(&quot;bsnmCode&quot;)
                    or props.get(&quot;REGNO&quot;)
                    or props.get(&quot;BSNMCODE&quot;)
                    or None
                )

                if not office_name:
                    skipped_count += 1
                    continue

                unique_value = license_no if license_no else office_name

                # -----------------------------
                # 여기서 RealEstateAgent 모델 필드명과 맞춰야 합니다.
                # 아래 필드명이 models.py와 다르면 수정하세요.
                # -----------------------------
                obj, created = RealEstateAgent.objects.update_or_create(
                    license_no=unique_value,
                    defaults={
                        &quot;office_name&quot;: office_name,
                        &quot;broker_name&quot;: broker_name,
                        &quot;road_address&quot;: road_addr,
                        &quot;jibun_address&quot;: jibun_addr,
                        &quot;phone_number&quot;: tel,
                        &quot;sigungu_name&quot;: sigungu_name,
                        &quot;raw_json&quot;: props,
                    }
                )

                if created:
                    created_count += 1
                else:
                    updated_count += 1

        self.stdout.write(
            self.style.SUCCESS(
                f&quot;저장 완료 - 생성: {created_count}개, 수정: {updated_count}개, 건너뜀: {skipped_count}개&quot;
            )
        )

        time.sleep(0.3)

</code></pre><p><a href="https://www.vworld.kr/dev/v4dv_2ddataguide2_s002.do?utm_source=chatgpt.com1">https://www.vworld.kr/dev/v4dv_2ddataguide2_s002.do?utm_source=chatgpt.com1</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ㅁㅁ]]></title>
            <link>https://velog.io/@hy_1023/%E3%85%81%E3%85%81</link>
            <guid>https://velog.io/@hy_1023/%E3%85%81%E3%85%81</guid>
            <pubDate>Mon, 20 Apr 2026 01:50:30 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hy_1023/post/d14733c1-d4d9-4f5e-823b-ee4d69dba459/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[공부기록3_멋쟁이사자처럼부트캠프+백엔드파이썬3기]]></title>
            <link>https://velog.io/@hy_1023/%EA%B3%B5%EB%B6%80%EA%B8%B0%EB%A1%9D3</link>
            <guid>https://velog.io/@hy_1023/%EA%B3%B5%EB%B6%80%EA%B8%B0%EB%A1%9D3</guid>
            <pubDate>Fri, 17 Apr 2026 06:20:57 GMT</pubDate>
            <description><![CDATA[<p>필드. 데이터 필드명 데이터명? 테이블 생성? 속성값<br>피그마  ERD 
(<a href="https://claude.ai/chat/5ea439d8-faba-4930-a033-8a663747fc6d">https://claude.ai/chat/5ea439d8-faba-4930-a033-8a663747fc6d</a>)</p>
<p>변수, 객체 , 리스트 , 함수형 클래스형 제너릭형 </p>
<p>파이브라인</p>
<p>model-&gt; url-&gt;view-&gt;templete</p>
<p>model-&gt; url-&gt; serealize -&gt;view -&gt; templete</p>
<hr>
<p>데이터를 찾는방법과  설계법 </p>
<p>각각 폴더들이 어떤 역할을 하는지   </p>
<p>view.set을 몰랐고 
drf 헷갈렸고 
api 와 그 데이터 연결받아오는게 헷갈렸음 
어드민. 
데이터를 가져와서 저장하고 그 다음에 마이그레이션 마이그레이트 </p>
<p>그런다음에 뷰로 봐야하는데  어드민슈퍼 명령어 
미리 템플릿 준비</p>
<p>앱...? 미리 준비? </p>
<p>각각 앱들에서 코드를 보면서 class가 들어가는 파일  path가 들어가는 파일 구별할줄알아야 하는데 못함</p>
<p>결국 이 모든것이  연결구조 그안에  해석 능력  그리고 파일의 이름연결구조 더 나아가서 문법 </p>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/7d5fbb5c-7bd6-4c88-ad2f-aa436c9fb9a6/image.png" alt=""></p>
<p>브라우저 기반 CRUD는 이미 완성됨
→ 구조를 더 정리해보고 싶다
→ 클래스형 / 제너릭 View를 배운다
→ 같은 데이터를 API로도 열어주고 싶다
→ DRF Serializer / ViewSet / Router를 사용한</p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/f9771acd-4e53-42b8-8fe8-8174d7f9b8cb/image.png" alt=""></p>
<p>브라우저에서 공부기록 CRUD 사용
→ 같은 데이터를 API 브라우저에서 JSON으로 확인
→ Insomnia로 POST / PATCH / DELETE 테스트
즉 이번 편은 “새로운 기능을 하나 더 만든다”기보다는, 이미 만든 기능을 더 Django답게 정리하고, API까지 확장하는 편이라고 이해하면 좋습니다.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/2adc1287-545c-41d5-8a7e-9f03bc16da08/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/7dfa6e7d-5a26-48ec-8846-2b0bb615310d/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/fe5c229f-d9ff-4abf-b69d-1744ba0ebe50/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/bf8b44dc-b272-4f9d-953a-3c7e736b764c/image.png" alt=""></p>
<h2 id="질문">질문</h2>
<p>-get post 처리구조?
-함수view,클래스형view,제너릭형view
-제너릭형view에서 장고패턴을 이해해야됨 
-장고DRF?
-
-
-</p>
<hr>
<p>5번부터 함수형 클래스형 제너릭형view에 대해서 </p>
<hr>
<p>12번부터 API에 대해서</p>
<hr>
<p>13번부터 DRF , Restframework </p>
<hr>
<p>14번  Serializer    ---&gt;  JSON데이터를 다루는 Form비슷한역할</p>
<hr>
<h2 id="일반-django-vs-django-drf-비교">일반 Django vs Django DRF 비교</h2>
<table>
<thead>
<tr>
<th>구성요소</th>
<th>일반 Django</th>
<th>Django DRF</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Model</strong></td>
<td>동일</td>
<td>동일 (변화 없음)</td>
</tr>
<tr>
<td><strong>URL</strong></td>
<td>거의 동일</td>
<td>router 추가됨</td>
</tr>
<tr>
<td><strong>View</strong></td>
<td>변화 있음</td>
<td>변화 있음</td>
</tr>
<tr>
<td><strong>Serializer</strong></td>
<td>없음</td>
<td><strong>새로 생김</strong></td>
</tr>
<tr>
<td><strong>Template</strong></td>
<td>HTML 렌더링</td>
<td>JSON 응답 (분리)</td>
</tr>
<tr>
<td><strong>Forms</strong></td>
<td>입력 검증에 사용</td>
<td>Serializer가 대체</td>
</tr>
</tbody></table>
<hr>
<h2 id="핵심-차이-설명">핵심 차이 설명</h2>
<p><strong>Model은 완전히 동일합니다.</strong></p>
<pre><code class="language-python"># 일반 Django도, DRF도 똑같이 씀
class Agent(models.Model):
    name = models.CharField(max_length=100)
    region = models.CharField(max_length=50)</code></pre>
<p><strong>Serializer가 새로 생깁니다</strong> — Form을 대체하는 역할이에요.</p>
<pre><code class="language-python"># DRF에서 새로 생기는 것
class AgentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Agent
        fields = &#39;__all__&#39;</code></pre>
<p><strong>View 방식이 달라집니다.</strong></p>
<pre><code class="language-python"># 일반 Django
def agent_list(request):
    agents = Agent.objects.all()
    return render(request, &#39;agents.html&#39;, {&#39;agents&#39;: agents})

# DRF
class AgentListView(APIView):
    def get(self, request):
        agents = Agent.objects.all()
        serializer = AgentSerializer(agents, many=True)
        return Response(serializer.data)  # JSON으로 반환</code></pre>
<p><strong>URL에 router가 추가됩니다</strong> (ViewSet 사용 시).</p>
<pre><code class="language-python"># 일반 Django
path(&#39;agents/&#39;, views.agent_list),

# DRF ViewSet 사용 시
router = DefaultRouter()
router.register(&#39;agents&#39;, AgentViewSet)
urlpatterns += router.urls</code></pre>
<hr>
<p>Model은 그대로, <strong>Serializer가 새로 생기고</strong>, <strong>View 방식이 바뀌고</strong>, <strong>URL에 router가 추가되는 것</strong>이 DRF의 변화입니다.</p>
<p>Form → Serializer로 역할이 넘어간다고 이해하면 가장 쉬워요. 더 궁금한 부분 있으시면 말씀해주세요!</p>
<hr>
<h3 id="가장-큰-차이입니다-render-대신-response를-사용하고-json을-반환합니다-하나의-view-안에서-getpost를-메서드로-구분해서-처리해요">가장 큰 차이입니다. render() 대신 Response()를 사용하고, JSON을 반환합니다. 하나의 View 안에서 GET/POST를 메서드로 구분해서 처리해요.</h3>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/98fe0a2d-09cd-4d0a-9612-73d399758d38/image.png" alt=""></p>
<h3 id="apiview-사용-시-url은-거의-동일합니다-viewset을-쓰면-router가-url을-자동-생성해줘서-훨씬-간단해져요-초보자는-apiview부터-시작하는-걸-추천합니다">APIView 사용 시 URL은 거의 동일합니다. ViewSet을 쓰면 Router가 URL을 자동 생성해줘서 훨씬 간단해져요. 초보자는 APIView부터 시작하는 걸 추천합니다.</h3>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/4f61ebe2-f6e3-410f-98d0-4a11ddc54c83/image.png" alt=""></p>
<h1 id="질문-1">질문</h1>
<p>-APIView 사용 시 URL은 거의 동일합니다. ViewSet을 쓰면 Router가 URL을 자동 생성해줘서 훨씬 간단해져요. 초보자는 APIView부터 시작하는 걸 추천합니다.</p>
<h3 id="drf에서-template은-화면html-구조만-담당합니다-데이터는-js가-api를-호출해서-가져와요-그래서-js는-반드시-static-폴더로-분리해야-합니다">DRF에서 Template은 화면(HTML 구조)만 담당합니다. 데이터는 JS가 API를 호출해서 가져와요. 그래서 JS는 반드시 static 폴더로 분리해야 합니다.</h3>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/8b99f294-edab-4320-a199-232102e758ce/image.png" alt=""></p>
<h1 id="질문-2">질문</h1>
<p>-DRF에서 Template은 화면(HTML 구조)만 담당합니다. 데이터는 JS가 API를 호출해서 가져와요. 그래서 JS는 반드시 static 폴더로 분리해야 합니다.</p>
<p>-Templete은 일반 Django 템플릿이 데이터 출력 
-DRF 템플릿은 화면만, 데이터는 API호출 </p>
<p>두개의 차이점? </p>
<hr>
<p>-기초세팅 헷갈림 이 앱이 어떤이유로 사용하고 왜 이런 데이터를 사용하는지 알아야함 </p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/fefec738-1861-4dea-9228-6419f751ec15/image.png" alt=""></p>
<hr>
<h3 id="settingspy에-rest_framework를-installed_apps에-추가하고-rest_framework-설정-블록이-새로-생깁니다-인증-방식-권한-페이지네이션-기본값을-여기서-전역으로-설정해요">settings.py에 rest_framework를 INSTALLED_APPS에 추가하고, REST_FRAMEWORK 설정 블록이 새로 생깁니다. 인증 방식, 권한, 페이지네이션 기본값을 여기서 전역으로 설정해요.</h3>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/41ffec96-33b3-41e6-abe9-47b54486f3dd/image.png" alt=""></p>
<hr>
<h1 id="결론">결론</h1>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/71bd56da-1582-4265-942f-11e0d8e60583/image.png" alt=""></p>
<hr>
<h1 id="질문-3">질문</h1>
<p>순서가    모델이 변경되면 마이그레이션 마이그레이트를 해주고 어드민설정  url  view  템플릿으로 화면에 띄어주기 순서로 알고있는데  이부분은 Django DRF 여서 순서가 달라지는거니?</p>
<p>좋은 질문이에요! 결론부터 말하면 <strong>기본 순서는 거의 동일</strong>한데, DRF에서 <strong>Serializer가 중간에 끼어들고</strong>, Template 대신 <strong>JS(fetch)로 화면을 띄우는 것</strong>만 달라져요.</p>
<hr>
<h2 id="순서-비교">순서 비교</h2>
<table>
<thead>
<tr>
<th>단계</th>
<th>일반 Django</th>
<th>Django DRF</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>Model 작성</td>
<td>Model 작성</td>
</tr>
<tr>
<td>2</td>
<td>makemigrations</td>
<td>makemigrations</td>
</tr>
<tr>
<td>3</td>
<td>migrate</td>
<td>migrate</td>
</tr>
<tr>
<td>4</td>
<td>admin 등록</td>
<td>admin 등록</td>
</tr>
<tr>
<td>5</td>
<td>URL 연결</td>
<td><strong>Serializer 작성</strong> ← 새로 추가</td>
</tr>
<tr>
<td>6</td>
<td>View 작성</td>
<td>URL 연결</td>
</tr>
<tr>
<td>7</td>
<td>Template으로 화면 출력</td>
<td>View 작성 (APIView/ViewSet)</td>
</tr>
<tr>
<td>8</td>
<td>—</td>
<td>Template + JS(fetch)로 화면 출력</td>
</tr>
</tbody></table>
<hr>
<h2 id="핵심-차이-딱-2가지">핵심 차이 딱 2가지</h2>
<p><strong>Serializer가 URL 전에 먼저 작성됩니다.</strong></p>
<p>View에서 Serializer를 import해서 써야 하기 때문에, View보다 먼저 만들어야 해요.</p>
<pre><code>Model → migrate → admin → Serializer → URL → View → 화면</code></pre><p><strong>화면 출력 방식이 달라집니다.</strong></p>
<pre><code class="language-python"># 일반 Django → View가 데이터를 Template에 직접 넘김
return render(request, &#39;list.html&#39;, {&#39;agents&#39;: agents})

# DRF → View는 JSON만 반환, JS가 API 호출해서 화면에 뿌림
return Response(serializer.data)</code></pre>
<hr>
<h2 id="실제-작업-순서-주거-플랫폼-기준">실제 작업 순서 (주거 플랫폼 기준)</h2>
<pre><code>1. models.py 작성        ← Agent, Property, Review 등
2. makemigrations
3. migrate
4. admin.py 등록         ← 관리자 페이지에서 데이터 확인용
5. serializers.py 작성   ← AgentSerializer, PropertySerializer 등
6. urls.py 연결
7. views.py 작성         ← APIView 또는 ViewSet
8. templates/ + static/js/ 작성  ← fetch로 API 호출해서 화면 출력</code></pre><p>기존에 알고 계신 순서에서 <strong>5번에 Serializer만 추가</strong>되고, 마지막 Template에서 <strong>JS fetch가 추가</strong>되는 거예요. 크게 달라지지 않으니 걱정 안 하셔도 됩니다!</p>
<hr>
<h1 id="질문-4">질문</h1>
<ol>
<li>models.py 작성        ← Agent, Property, Review 등</li>
<li>makemigrations</li>
<li>migrate</li>
<li>admin.py 등록         ← 관리자 페이지에서 데이터 확인용</li>
<li>serializers.py 작성   ← AgentSerializer, PropertySerializer 등</li>
<li>urls.py 연결</li>
<li>views.py 작성         ← APIView 또는 ViewSet</li>
<li>templates/ + static/js/ 작성  ← fetch로 API 호출해서 화면 출력</li>
</ol>
<p>1번 모델에대해 설명과  5번의 종류에 대해 7번 차이  8번의 기초적인개념에 대해 설명</p>
<hr>
<p>property 속성 
agent 대리인 행위자 
statics  정적 --&gt; 더 알아보기 
API 호출
const container
fetch
catch
.then</p>
<hr>
<p>4개 주제를 하나씩 자세하게 설명해드릴게요.</p>
<hr>
<h2 id="1-modelspy--데이터베이스-설계도">1. models.py — 데이터베이스 설계도</h2>
<p>Model은 <strong>DB 테이블을 Python 코드로 표현한 것</strong>이에요. 클래스 하나 = 테이블 하나입니다.</p>
<pre><code class="language-python">from django.db import models

class Agent(models.Model):
    # CharField → 문자열 (max_length 필수)
    name = models.CharField(max_length=100)
    region = models.CharField(max_length=50)

    # FloatField → 소수점 숫자
    avg_rating = models.FloatField(default=0.0)

    # BooleanField → True/False
    is_deleted = models.BooleanField(default=False)

    # DateTimeField → 날짜+시간
    created_at = models.DateTimeField(auto_now_add=True)  # 생성 시 자동 저장
    updated_at = models.DateTimeField(auto_now=True)      # 수정 시 자동 갱신

    # ForeignKey → 다른 테이블과 연결 (1:N 관계)
    user = models.ForeignKey(
        &#39;accounts.User&#39;,
        on_delete=models.CASCADE  # User 삭제 시 Agent도 삭제
    )</code></pre>
<p>자주 쓰는 필드 타입 정리:</p>
<table>
<thead>
<tr>
<th>필드</th>
<th>용도</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>CharField</code></td>
<td>짧은 문자열</td>
<td>이름, 주소</td>
</tr>
<tr>
<td><code>TextField</code></td>
<td>긴 문자열</td>
<td>리뷰 내용</td>
</tr>
<tr>
<td><code>IntegerField</code></td>
<td>정수</td>
<td>가격, 층수</td>
</tr>
<tr>
<td><code>FloatField</code></td>
<td>소수</td>
<td>평점, 면적</td>
</tr>
<tr>
<td><code>BooleanField</code></td>
<td>True/False</td>
<td>삭제여부</td>
</tr>
<tr>
<td><code>DateTimeField</code></td>
<td>날짜+시간</td>
<td>생성일</td>
</tr>
<tr>
<td><code>ForeignKey</code></td>
<td>1:N 관계</td>
<td>매물→중개사</td>
</tr>
<tr>
<td><code>ManyToManyField</code></td>
<td>N:N 관계</td>
<td>북마크</td>
</tr>
</tbody></table>
<hr>
<h2 id="5-serializerspy--종류-3가지">5. serializers.py — 종류 3가지</h2>
<p>Serializer는 <strong>DB 데이터 ↔ JSON 변환 + 입력값 검증</strong>을 담당해요. 종류가 3가지 있어요.</p>
<p><strong>종류 1 — <code>Serializer</code> (직접 다 정의)</strong></p>
<pre><code class="language-python">from rest_framework import serializers

class AgentSerializer(serializers.Serializer):
    # 필드를 하나하나 직접 선언해야 함
    id = serializers.IntegerField(read_only=True)
    name = serializers.CharField(max_length=100)
    region = serializers.CharField(max_length=50)

    def create(self, validated_data):
        return Agent.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.name = validated_data.get(&#39;name&#39;, instance.name)
        instance.save()
        return instance</code></pre>
<p>→ 유연하지만 코드가 많아짐. 모델과 관계없는 데이터 처리할 때 사용.</p>
<hr>
<p><strong>종류 2 — <code>ModelSerializer</code> (가장 많이 씀)</strong></p>
<pre><code class="language-python">from rest_framework import serializers
from .models import Agent

class AgentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Agent                    # 어떤 모델인지
        fields = [&#39;id&#39;, &#39;name&#39;, &#39;region&#39;, &#39;avg_rating&#39;]  # 노출할 필드
        # fields = &#39;__all__&#39;            # 전체 필드 노출
        read_only_fields = [&#39;avg_rating&#39;, &#39;created_at&#39;]  # 읽기 전용

    # 특정 필드 검증 추가
    def validate_name(self, value):
        if len(value) &lt; 2:
            raise serializers.ValidationError(&quot;이름이 너무 짧습니다&quot;)
        return value</code></pre>
<p>→ Model 기반으로 자동 생성. 코드 짧고 편함. <strong>3차 프로젝트에서 주로 이걸 사용</strong>.</p>
<hr>
<p><strong>종류 3 — 중첩 Serializer (연결된 데이터 함께 출력)</strong></p>
<pre><code class="language-python">class ReviewSerializer(serializers.ModelSerializer):
    class Meta:
        model = Review
        fields = [&#39;id&#39;, &#39;rating&#39;, &#39;content&#39;]

class AgentSerializer(serializers.ModelSerializer):
    # Agent 조회 시 리뷰 목록도 함께 출력
    reviews = ReviewSerializer(many=True, read_only=True)

    class Meta:
        model = Agent
        fields = [&#39;id&#39;, &#39;name&#39;, &#39;region&#39;, &#39;avg_rating&#39;, &#39;reviews&#39;]</code></pre>
<p>→ 연결된 테이블 데이터를 한 번에 같이 보여줄 때 사용.</p>
<hr>
<h2 id="7-viewspy--apiview-vs-viewset-차이">7. views.py — APIView vs ViewSet 차이</h2>
<p><strong><code>APIView</code> — HTTP 메서드를 직접 제어</strong></p>
<pre><code class="language-python">from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class AgentListView(APIView):
    # GET 요청 → 목록 조회
    def get(self, request):
        agents = Agent.objects.filter(is_deleted=False)
        serializer = AgentSerializer(agents, many=True)
        return Response(serializer.data)

    # POST 요청 → 생성
    def post(self, request):
        serializer = AgentSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=201)
        return Response(serializer.errors, status=400)

class AgentDetailView(APIView):
    # GET → 단건 조회
    def get(self, request, pk):
        agent = Agent.objects.get(pk=pk)
        serializer = AgentSerializer(agent)
        return Response(serializer.data)

    # PUT → 수정
    def put(self, request, pk):
        agent = Agent.objects.get(pk=pk)
        serializer = AgentSerializer(agent, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=400)

    # DELETE → 삭제
    def delete(self, request, pk):
        agent = Agent.objects.get(pk=pk)
        agent.is_deleted = True  # Soft Delete
        agent.save()
        return Response(status=204)</code></pre>
<hr>
<p><strong><code>ViewSet</code> — CRUD를 자동으로 만들어줌</strong></p>
<pre><code class="language-python">from rest_framework.viewsets import ModelViewSet

class AgentViewSet(ModelViewSet):
    queryset = Agent.objects.filter(is_deleted=False)
    serializer_class = AgentSerializer
    # 끝. GET/POST/PUT/DELETE 전부 자동 생성됨</code></pre>
<hr>
<p><strong>핵심 차이 정리:</strong></p>
<table>
<thead>
<tr>
<th></th>
<th>APIView</th>
<th>ViewSet</th>
</tr>
</thead>
<tbody><tr>
<td>코드량</td>
<td>많음</td>
<td>적음</td>
</tr>
<tr>
<td>제어</td>
<td>직접 제어</td>
<td>자동 생성</td>
</tr>
<tr>
<td>URL</td>
<td>직접 연결</td>
<td>Router 자동 생성</td>
</tr>
<tr>
<td>추천 대상</td>
<td>초보자</td>
<td>구조 익숙해진 후</td>
</tr>
</tbody></table>
<p>초보자는 <strong>APIView 먼저</strong> 익히고, 익숙해지면 ViewSet으로 넘어가는 게 좋아요.</p>
<hr>
<h2 id="8-templates--staticjs--기초-개념">8. templates + static/js — 기초 개념</h2>
<p>일반 Django는 View가 데이터를 Template에 직접 넘겼지만, DRF는 이렇게 분리돼요.</p>
<pre><code>Template  →  화면 구조(HTML)만 담당
static/js →  API 호출해서 데이터 가져와 화면에 뿌림</code></pre><p><strong>폴더 구조:</strong></p>
<pre><code>properties/
  templates/
    properties/
      list.html       ← HTML 구조만 있음
  static/
    js/
      agent_list.js   ← fetch로 API 호출</code></pre><p><strong>list.html — 구조만 있고 데이터 없음:</strong></p>
<pre><code class="language-html">&lt;body&gt;
  &lt;div id=&quot;agent-list&quot;&gt;
    &lt;!-- JS가 여기에 데이터를 채워줌 --&gt;
  &lt;/div&gt;

  &lt;!-- JS 파일 연결 --&gt;
  &lt;script src=&quot;{% static &#39;js/agent_list.js&#39; %}&quot;&gt;&lt;/script&gt;
&lt;/body&gt;</code></pre>
<p><strong>agent_list.js — API 호출해서 데이터 출력:</strong></p>
<pre><code class="language-javascript">// 1. API 호출
fetch(&#39;/api/agents/&#39;)

  // 2. JSON으로 변환
  .then(response =&gt; response.json())

  // 3. 화면에 출력
  .then(data =&gt; {
    const container = document.getElementById(&#39;agent-list&#39;)

    data.forEach(agent =&gt; {
      container.innerHTML += `
        &lt;div class=&quot;agent-card&quot;&gt;
          &lt;h3&gt;${agent.name}&lt;/h3&gt;
          &lt;p&gt;지역: ${agent.region}&lt;/p&gt;
          &lt;p&gt;평점: ${agent.avg_rating}&lt;/p&gt;
        &lt;/div&gt;
      `
    })
  })

  // 4. 에러 처리
  .catch(error =&gt; {
    console.error(&#39;오류 발생:&#39;, error)
  })</code></pre>
<p><strong>흐름 한 줄 요약:</strong></p>
<pre><code>사용자가 페이지 열기
  → HTML(Template) 로딩
  → JS 실행 → API(/api/agents/) 호출
  → View가 JSON 반환
  → JS가 JSON 받아서 화면에 출력</code></pre><p>이 흐름이 DRF의 핵심이에요. Template은 틀만 잡고, 실제 데이터는 JS가 API를 통해 가져오는 구조입니다. 궁금한 부분 있으면 더 질문해 주세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트2일차_20260416]]></title>
            <link>https://velog.io/@hy_1023/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B82%EC%9D%BC%EC%B0%A820260416</link>
            <guid>https://velog.io/@hy_1023/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B82%EC%9D%BC%EC%B0%A820260416</guid>
            <pubDate>Thu, 16 Apr 2026 02:56:22 GMT</pubDate>
            <description><![CDATA[<p>첫페이지는 인덱스.HTML 페이지  --&gt; 첫페이지는 아직안만들거임 </p>
<p>그 다음에  질문을 고객이 했을때  원하는 정보 나오도록 </p>
<hr>
<p>두번째 페이지에는 정보들이 다 모아져 있어야 한다. </p>
<p>데이터를 무엇을 담을 건지 보여줄건지를 피그마에 기능구현하나하나  모아놓기 --&gt;리스트페이지가되는것 </p>
<hr>
<p>리스페이지를 피그마로 그려놔야  오늘 장고세팅을 하는데 화면을 구현하는데 비슷하게 나오게 만들수 있다. </p>
<hr>
<ol>
<li>VS 에서 세팅설계하고 </li>
<li>화면설계 </li>
</ol>
<hr>
<p>장고세팅 가상환경 DRF 세팅  템플릿분리 까지</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[취업_디코]]></title>
            <link>https://velog.io/@hy_1023/%EC%B7%A8%EC%97%85</link>
            <guid>https://velog.io/@hy_1023/%EC%B7%A8%EC%97%85</guid>
            <pubDate>Tue, 14 Apr 2026 07:23:10 GMT</pubDate>
            <description><![CDATA[<h2 id="기술문서-중요">기술문서 중요</h2>
<h2 id="기술문서면접-_-프로젝트관련-기술면접--cs-내가-만든-프로젝트-관련-기술-면점-pd">기술문서면접 _ 프로젝트관련 기술면접  CS/ 내가 만든 프로젝트 관련 기술 면점 PD</h2>
<h3 id="일대일-면접할예정">일대일 면접할예정</h3>
<h3 id="내가-만든것에-대한-설명">내가 만든것에 대한 설명</h3>
<h3 id="여러가지-기능을-넣기보다-하나두개-완벽하게-화면에-구현해야한다">여러가지 기능을 넣기보다 하나~두개 완벽하게 화면에 구현해야한다.</h3>
<h3 id="모니터링-세팅은-나의-몫-말단이-하는것">모니터링 세팅은 나의 몫 말단이 하는것</h3>
<h3 id="여기서-임계치-달아놓는거는-당연하게--쿠버와-배포-연습해야한다">여기서 임계치 달아놓는거는 당연하게  쿠버와 배포 연습해야한다.</h3>
<h3 id="지금까지-배운-내용과-흐름도를-알아야-한다">지금까지 배운 내용과 흐름도를 알아야 한다.</h3>
<h3 id=""></h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[29_1 쿠버네티스(K8s)]]></title>
            <link>https://velog.io/@hy_1023/291-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4K8s</link>
            <guid>https://velog.io/@hy_1023/291-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4K8s</guid>
            <pubDate>Mon, 13 Apr 2026 06:07:20 GMT</pubDate>
            <description><![CDATA[<p>하나의 프로그램이라고 생각 </p>
<p>도커가 컨테이너가 관리자</p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/0bb51ccc-3094-4d31-9e71-a79074b8ba8a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/590cb511-6487-4f5a-b20d-1d5103df82e1/image.png" alt=""></p>
<p>쿠버네티스는 서버위에서 돌아가는 운영자 </p>
<p>물리적인서버  - 내pc</p>
<p>물리적인 서버 - ec2</p>
<p>ec2 안에  도커컨테이너 놓고 그걸 운영하는애가 쿠버네티스 </p>
<hr>
<p>장고에서는 따로 </p>
<p>여기서는 장고랑 같이 쓰임 </p>
<hr>
<p>서버는 큰 건물 </p>
<p>컨테이너  각각방</p>
<p>장고  fast api  입주자 </p>
<p>쿠버  관리자 </p>
<hr>
<p>서비스끼리 어떻게 연결 하는지 서로 어떤영향주는지
코드 흐름 알아야한다. </p>
<p>ai버튼  기능 누를때 내부엥서 어떻게 처리되는지 </p>
<p>알람파카 추가 되면 어떤파일을 수정해야하는지 </p>
<p>--&gt;  운영하는데 있어서 세부적인 옵션 생각 </p>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/65dbf76d-1b5d-41be-9425-eef9962a941b/image.png" alt=""></p>
<p>네임스페이스에서 ,,,,  했던작업</p>
<p>postgres -- 세가지의 단계로  상태 / 서비스 / 저장생성</p>
<p>redis </p>
<p>fast api  </p>
<p>django </p>
<p>쿠버네티스에 붙여주는 것..? </p>
<p>코피그 </p>
<hr>
<p>전체적흐름.......................</p>
<p>+</p>
<p>pod 추가할때 어떤걸 수정해야하고 연관되어있나 </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ai 활용과  프로젝트 무엇?]]></title>
            <link>https://velog.io/@hy_1023/ai-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@hy_1023/ai-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Thu, 09 Apr 2026 09:08:23 GMT</pubDate>
            <description><![CDATA[<p>의사코드 </p>
<p>어떻게 하면 더 빨리 남들보다 빠르게 </p>
<p>아이디어를 눈앞에 보일수있는지와</p>
<p>수정..사항</p>
<p>crud 는 거의 똑같아서  큰흐름 맥락위주로 보면 된다. </p>
<p>그러나 딥하게 배운다고 하면 알아야한다. </p>
<hr>
<p>우선.  설치. </p>
<p><a href="https://docs.unity3d.com/kr/530/Manual/InstallingUnity.html">https://docs.unity3d.com/kr/530/Manual/InstallingUnity.html</a></p>
<p><a href="https://docs.unity3d.com/kr/530/Manual/InstallingUnity.html">https://docs.unity3d.com/kr/530/Manual/InstallingUnity.html</a></p>
<p><a href="https://claude.ai/chat/dfc6fc4f-7c28-4a4b-a50e-6a9fac922bb8">https://claude.ai/chat/dfc6fc4f-7c28-4a4b-a50e-6a9fac922bb8</a></p>
<hr>
<ul>
<li><p>자신의 일을 글로 정리해본뒤 그러고 나서 방법을 찾기 
  처음부터 도구만 찾다보녀 금방 지침 </p>
</li>
<li><p>일하면서 내가 필요하다고 생각한 부분에 대해 현재 존재하는지 체크</p>
</li>
<li><p>리얼타임 메타 예전에 봤던거 찾아보기  </p>
</li>
<li><p>현업에서 필요한 니즈가 무엇이고 어떤 트랜드인지, </p>
</li>
<li><p>그리고 내가 필요하다고 생각한 니즈? 
  무엇인지 생각을 글로 정리하기 </p>
</li>
<li><h2 id="몇가지-플랜을-제시하기--안될수도-있으니까">몇가지 플랜을 제시하기  (안될수도 있으니까)</h2>
</li>
<li><p>피드백 마야정보 (유니티 언리얼 정보)서로 서버통신이 가능한지<br>즉,  이 프로젝트는 데이터를 보내고 받는 &quot;데이터 전송&quot;이  포인트 </p>
</li>
<li><p>첫번째로 체크 할 사항은 서로 서버통신이 가능한지  </p>
</li>
<li><p>현업에서의 니즈..... 어떤 프로젝트를 할수있는지와  눈에 띄는지  </p>
</li>
<li><p>두달안에 실현가능한지 </p>
</li>
<li><p>내가 프로젝트에서 사용할 툴과 빠른속도 그리고 트렌드에 민감</p>
</li>
<li><p>그 외 내가 공부했던 부분은 놓치말고 계속 포폴 쌓아가기 </p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django 기초 - 공부시간 기록기 만들기(2)_헷갈리는부분 ]]></title>
            <link>https://velog.io/@hy_1023/Django-%EA%B8%B0%EC%B4%88-%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B02-lzzcysv6</link>
            <guid>https://velog.io/@hy_1023/Django-%EA%B8%B0%EC%B4%88-%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B02-lzzcysv6</guid>
            <pubDate>Thu, 09 Apr 2026 01:45:02 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.figma.com/design/wDh3su4KrlhkzOM1d7vKBT/Django-%EA%B8%B0%EC%B4%88---%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-2-?node-id=17-98&amp;p=f&amp;t=huYfHj2496lbwPcI-0">https://www.figma.com/design/wDh3su4KrlhkzOM1d7vKBT/Django-%EA%B8%B0%EC%B4%88---%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-2-?node-id=17-98&amp;p=f&amp;t=huYfHj2496lbwPcI-0</a></p>
<p>헷갈리는 단어 체크 </p>
<ul>
<li><p>1편에서는  데이터를 admin에서만 넣고 테스트 ? 실제 웹페이지에서 직접데이터 넣고 테스트? </p>
</li>
<li><p>2번째 교안의 목표 </p>
<ul>
<li><p>모델폼?  ModModel form?</p>
</li>
<li><p>함수형 view 기준의 CRUD? </p>
</li>
<li><p>CRUD ? 생성, 상세 , 수정 , 삭제 각각 어떻게 구현되는지 체득?   </p>
</li>
<li><p>함수형? 클래식? 제너릭? </p>
</li>
<li><p>브라우저 중심 테이터흐름이해.. 브라우저?</p>
</li>
<li><p>HTML 폼 입력</p>
</li>
<li><p>POST 란?  그 반대말? 그외 종류는 무엇이 있는지  </p>
</li>
<li><p>검증?</p>
</li>
<li><p>저장</p>
</li>
<li><p>redirect 흐름 이해?  뜻? 그반대의미또는 그외 종류 ? </p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/9190aa37-1d5a-4d17-b48b-58cecc0dd955/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>-이 흐름이 이해되어야 다음 교안에서 클래스형 View, 제너릭 View, DRF까지 자연스럽게 연결됩니다.     --&gt;  왜??/   
-DRF 는 무엇인가. 
- 함수 클래스 제너릭 종류는  VIEW 밖에 없나 ?  </code></pre><hr>
<p>27번. 마지막 부분  2차 교안에서 핵심 흐름</p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/c2701061-bde3-4046-a9ab-56a27a95c1a1/image.png" alt=""></p>
<p>-모델폼작성 
    -브라우저 기반 CRUD? 
    -C생성 D상세 U수정 D삭제 P페이지네이션 --&gt; 이부분이 ? CRUD 라는건가? 
    -그리고 생성 / 수정 흐름은 특히 아래 패턴을 꼭 기억해야 합니다.
        -GET 요청이란?  의미와 역할 그외 종류
         - 빈 폼 또는 기존 값이 채워진 폼 보여주기
        -POST 요청이란?  의미와 역할 그외 종류 
        -사용자가 제출한 값 받기  뭘로 받는지 
        -form.is_valid() 검증 언제 쓰이는지
        -form.save() 저장  의미?  언제 쓰이는지 
        -redirect() 이동  역할과 의미 그외종류     </p>
<p>   -이 패턴은 Django에서 정말 자주 반복됩니다. -- &gt; 핵심? </p>
<p>-28. 함수형 View 기준 CRUD 정리?</p>
<p>   <img src="https://velog.velcdn.com/images/hy_1023/post/ac9db4c1-3d8f-417b-8c9f-b2c259d43e93/image.png" alt=""></p>
<p>-함수형 View란? 
    -함수형 View 기준으로 CRUD 전체 구조를 이해하는 것이 핵심이
    -다음에 클래스 view 와 제너릭 view 넘어갈때. 무엇이 다른가? 
    -현재 2편에서 만든 함수형 view 종류? 총 5개 
    -즉 Django CRUD의 가장 기본 형태를 함수형으로 먼저 체득한 것--&gt; 장고crud 기본형태를 함수형으로 먼저 체득 --&gt;  무슨의미 </p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/d441ace4-e03e-4543-811e-13b3ce214426/image.png" alt=""></p>
<ul>
<li>30.체크리스트에서  <ul>
<li>모델폼 형성</li>
<li>C생성 D상세 U수정 D삭제 P페이지네이션 </li>
<li>url -&gt; view -&gt; templete 방식으로 진행이 되는거 같은데 상세템플릿을 만든 다음 목록에서 상세 페이지로 이동 할수있다..?  갑자기왜? </li>
<li>수정에서  url view  그 다음 새로운 템플릿이 아닌 기존값이 채워진 수정 폼이 열리는 부분  </li>
<li>수정 후 상세 페이지에서 반영된 결과를 볼 수 있다. --&gt; 코드가 분석해야한다. </li>
<li>삭제에서  url -&gt; view -&gt; templete 방식 까지는 이해되지만, 그 다음이 이해가 어려움 </li>
<li>삭제 전 확인 페이지가 나온다.</li>
<li>삭제 후 목록에서 데이터가 사라진다.</li>
<li>페이지 네이션 이란? </li>
<li>데이터 6개 이상으로 페이지 이동을 확인했다.</li>
</ul>
</li>
</ul>
<ol start="31">
<li>결론 </li>
</ol>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/ee528c9b-36eb-4502-b225-f8dd3f813e2e/image.png" alt=""></p>
<p>-1차와 2차의 다른점  즉 프로젯트파일 장고 파일 어드민설치 그안에 앱형성 임시테스트하기위해 어드민으로 먼저 임시 테스트하고 임시테스트 성공하면 1차에서 흐름 이해도를 위해  앱 여러개가 아닌 앱 하나만 만들어서 그안에 study models.py 에 함수뷰로 만들기? </p>
<p>-2차에서는 모델파일을 함수뷰로 하는게 아닌 장고내장함수의 모델폼을 이용하여<br>    -C생성 D상세 U수정 D삭제 P페이지네이션  브라우저 중심 CRUD 테스트
   -브라우저 중심 CRUD 테스트이란 무엇인가 ? </p>
<p>   -즉 장고로 데이토를 보여줄수도 만들수도 수정할수도 삭제할수도있는 기본적인웹서비스를 완성 시킨것. </p>
<p>   -여기에서 중요한것은 
       -GET 폼 보여주기 
    -POST  검증 저장 redirect  </p>
<p>   --&gt; 이패턴이 Django Form 처리의 핵심! 모르겠음... </p>
<ul>
<li><p>3차 교안에서는  “브라우저 기반 CRUD”를 넘어서, Django를 더 Django답게 사용하는 구조와 API 확장 흐름까지 가게 됩니다.</p>
<p>  -함수형 View 복습</p>
<ul>
<li>클래스형 View</li>
<li>→ 제너릭 View</li>
<li>→ DRF Serializer</li>
<li>→ ViewSet</li>
<li>→ Router</li>
<li>→ API 테스트 </li>
</ul>
</li>
</ul>
<hr>
<h1 id="정리한것에-찾기">정리한것에 찾기</h1>
<ul>
<li>1편에서는 데이터를 admin에서만 넣고 테스트 ? 실제 웹페이지에서 직접데이터 넣고 테스트?</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/bad9648b-db57-4d20-86c3-ad87dd9183e9/image.png" alt=""></p>
<ul>
<li>모델폼? ModModel form? </li>
</ul>
<h2 id="1편-순서기억-이해">1편 순서기억 이해</h2>
<h3 id="form--modelform을-쓰는-이유">Form / ModelForm을 쓰는 이유</h3>
<h3 id="나의질문-폼이랑-모델폼차이가-이해가-안되신다는건가용">나의질문 폼이랑 모델폼차이가 이해가 안되신다는건가용??</h3>
<p>Study 모델 정의
→ ModelForm 작성
→ 폼에서 입력값 검증
→ form.save()로 모델 저장</p>
<h3 id="답변">답변</h3>
<p>스터디 모델을 1편에서 만들었잖아요?
그 모델이랑 연결되는 form을 만들라는거에용
모델과 연관성있는 것 무언가 입력을 받는 구조의 폼이라고 생각 </p>
<p>Form은
그냥 입력창을 만드는 도구
어떤 값을 받을지 직접 다 적어줘야 함
저장도 직접 해야 함</p>
<p>즉, “입력만 받는 일반 양식”이라고 이해하시면 됩니다.</p>
<p>ModelForm은
모델을 기준으로 폼을 쉽게 만드는 도구
모델 필드를 바탕으로 입력창을 만들 수 있음
검증도 도와주고, form.save()로 DB 저장도 쉬움</p>
<p>즉, “모델이랑 연결된 폼”이라고 이해하시면 됩니다.</p>
<p>우리가 템플릿에서 보는 <form> 태그는
사용자가 값을 입력해서 보내는 HTML 영역이에요!</p>
<p>사용자가 입력한 값이 서버로 전달되면,
서버에서 ModelForm이 그 값을 받아 검증하고,
문제가 없으면 저장한다고 생각하시면 됩니당</p>
<h2 id="나의질문">나의질문</h2>
<p>study 앱에  폼을 만들고 그 폼이라는것은 그냥 앱 생성할때마다 만드는 폼이라고 생각하면되나요.. 그리고 그안에   CRUS페이지까지  스터디앱에 만드는거죠? </p>
<h2 id="답변-1">답변</h2>
<p>폼은 앱 만들 때 무조건 만드는 게 아니라, 사용자의 입력을 받아야 할 때 만드는 거예요! 항상 만드는건 아니에용 그리고 Study 앱을 만들었으니까, Study 관련 CRUD 페이지도 그 앱 안에서 같이 만듭니다  </p>
<hr>
<h2 id="form-vs-modelform-적용-범위">Form vs ModelForm 적용 범위</h2>
<p><strong>아니요, 둘 다 모델 파일과 독립적으로 사용할 수 있습니다.</strong></p>
<hr>
<h3 id="formsform--모델과-무관"><code>forms.Form</code> — 모델과 <strong>무관</strong></h3>
<pre><code class="language-python">class ContactForm(forms.Form):
    name = forms.CharField()
    email = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)</code></pre>
<ul>
<li>모델 없이 순수하게 입력값 처리/검증만 할 때 사용</li>
<li>예: 문의 폼, 검색 폼, 로그인 폼, 계산기 폼 등</li>
</ul>
<hr>
<h3 id="formsmodelform--모델과-연결됨"><code>forms.ModelForm</code> — 모델과 <strong>연결됨</strong></h3>
<pre><code class="language-python">class StudyForm(forms.ModelForm):
    class Meta:
        model = Study  # ← 특정 모델에 종속
        fields = [...]</code></pre>
<ul>
<li>반드시 <code>Meta.model</code>에 연결할 모델이 필요</li>
<li><code>form.save()</code>로 DB에 바로 저장 가능</li>
</ul>
<hr>
<h3 id="정리">정리</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>모델 필요 여부</th>
<th>DB 저장</th>
</tr>
</thead>
<tbody><tr>
<td><code>forms.Form</code></td>
<td>❌ 불필요</td>
<td>직접 처리해야 함</td>
</tr>
<tr>
<td><code>forms.ModelForm</code></td>
<td>✅ 필수</td>
<td><code>form.save()</code>로 자동</td>
</tr>
</tbody></table>
<p>즉, <strong><code>ModelForm</code>만 모델 파일에 해당</strong>되고, <code>Form</code>은 모델 없이 어디서든 독립적으로 사용할 수 있습니다.</p>
<hr>
<h2 id="1-formsform이-필요한-때">1. <code>forms.Form</code>이 필요한 때</h2>
<p>모델에 저장할 필요 없이 <strong>입력값만 처리</strong>할 때 사용합니다.</p>
<pre><code class="language-python"># 예시 1 - 검색 폼
class SearchForm(forms.Form):
    keyword = forms.CharField()
    # 검색어를 받아서 필터링만 할 뿐, DB에 저장 안 함

# 예시 2 - 로그인 폼
class LoginForm(forms.Form):
    username = forms.CharField()
    password = forms.CharField(widget=forms.PasswordInput)
    # 인증만 하고 저장 X

# 예시 3 - 문의/이메일 폼
class ContactForm(forms.Form):
    email = forms.EmailField()
    message = forms.CharField()
    # 이메일로 전송만 하고 저장 X</code></pre>
<hr>
<h2 id="2-메서드라는-표현에-대해">2. &quot;메서드&quot;라는 표현에 대해</h2>
<p><strong>정확히는 구분해서 불러야 합니다.</strong></p>
<table>
<thead>
<tr>
<th>용어</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><strong>클래스(Class)</strong></td>
<td>설계도 전체</td>
<td><code>StudyForm</code>, <code>LoginForm</code></td>
</tr>
<tr>
<td><strong>메서드(Method)</strong></td>
<td>클래스 안의 함수</td>
<td><code>clean_minutes()</code>, <code>save()</code></td>
</tr>
<tr>
<td><strong>필드(Field)</strong></td>
<td>클래스 안의 변수/속성</td>
<td><code>title</code>, <code>email</code></td>
</tr>
</tbody></table>
<pre><code class="language-python">class StudyForm(forms.ModelForm):  # ← 클래스

    title = forms.CharField()      # ← 필드

    def clean_minutes(self):       # ← 메서드
        ...</code></pre>
<p>그래서</p>
<ul>
<li><code>StudyForm</code> 자체 → <strong>클래스</strong></li>
<li><code>clean_minutes()</code> → <strong>메서드</strong></li>
<li><code>forms.Form</code>, <code>forms.ModelForm</code> → <strong>클래스를 상속</strong>받는 것</li>
</ul>
<p>&quot;Form이랑 ModelForm 메서드야?&quot; 라고 하면 엄밀히는 <strong>클래스</strong>라고 표현하는 게 맞습니다.</p>
<hr>
<ol start="3">
<li>함수형? 클래식? 제너릭?</li>
</ol>
<pre><code>
함수형 View (FBV, Function-Based View)

Django에서 뷰를 **함수로 작성**하는 방식이에요.

```python
# views.py
from django.shortcuts import render

def study_list(request):
    studies = Study.objects.all()
    return render(request, &#39;study/list.html&#39;, {&#39;studies&#39;: studies})</code></pre><p>CBV (Class-Based View) 와 비교</p>
<pre><code class="language-python"># ❌ FBV
def study_list(request):
    studies = Study.objects.all()
    return render(request, &#39;study/list.html&#39;, {&#39;studies&#39;: studies})

# ✅ CBV
class StudyListView(ListView):
    model = Study
    template_name = &#39;study/list.html&#39;</code></pre>
<table>
<thead>
<tr>
<th></th>
<th>FBV</th>
<th>CBV</th>
</tr>
</thead>
<tbody><tr>
<td>구조</td>
<td>함수</td>
<td>클래스</td>
</tr>
<tr>
<td>난이도</td>
<td>쉬움</td>
<td>어려움</td>
</tr>
<tr>
<td>코드량</td>
<td>많음</td>
<td>적음</td>
</tr>
<tr>
<td>유연성</td>
<td>높음</td>
<td>낮음</td>
</tr>
</tbody></table>
<p>Django 뷰의 종류: 함수뷰 vs 클래스뷰 vs 제너릭뷰</p>
<ol>
<li>함수 기반 뷰 (Function-Based View, FBV)</li>
</ol>
<pre><code class="language-python">from django.shortcuts import render, get_object_or_404

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, &#39;blog/post_detail.html&#39;, {&#39;post&#39;: post})</code></pre>
<p><strong>특징</strong></p>
<ul>
<li>가장 단순하고 직관적</li>
<li>흐름이 명확해서 읽기 쉬움</li>
<li>HTTP 메서드 분기를 직접 처리해야 함 (<code>if request.method == &#39;POST&#39;:</code>)</li>
<li>재사용성이 낮음</li>
</ul>
<ol start="2">
<li>클래스 기반 뷰 (Class-Based View, CBV)</li>
</ol>
<pre><code class="language-python">from django.views import View

class PostDetailView(View):
    def get(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        return render(request, &#39;blog/post_detail.html&#39;, {&#39;post&#39;: post})

    def post(self, request, pk):
        # POST 요청 처리
        ...</code></pre>
<p><strong>특징</strong></p>
<ul>
<li>HTTP 메서드(GET, POST 등)를 메서드로 자동 분기</li>
<li>상속과 믹스인(Mixin)으로 코드 재사용 가능</li>
<li>복잡한 뷰일수록 구조화하기 유리</li>
<li>FBV보다 초기 학습 곡선이 있음</li>
</ul>
<ol start="3">
<li>제너릭 뷰 (Generic View)</li>
</ol>
<p>CBV를 <strong>더 추상화</strong>한 것으로, Django가 CRUD 패턴을 미리 구현해 놓은 뷰</p>
<pre><code class="language-python">from django.views.generic import ListView, DetailView, CreateView

class PostListView(ListView):
    model = Post
    template_name = &#39;blog/post_list.html&#39;
    context_object_name = &#39;posts&#39;

class PostDetailView(DetailView):
    model = Post

class PostCreateView(CreateView):
    model = Post
    fields = [&#39;title&#39;, &#39;content&#39;]
    success_url = &#39;/posts/&#39;</code></pre>
<p><strong>주요 종류</strong></p>
<table>
<thead>
<tr>
<th>클래스</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td><code>ListView</code></td>
<td>목록 조회</td>
</tr>
<tr>
<td><code>DetailView</code></td>
<td>단일 객체 조회</td>
</tr>
<tr>
<td><code>CreateView</code></td>
<td>객체 생성</td>
</tr>
<tr>
<td><code>UpdateView</code></td>
<td>객체 수정</td>
</tr>
<tr>
<td><code>DeleteView</code></td>
<td>객체 삭제</td>
</tr>
<tr>
<td><code>TemplateView</code></td>
<td>단순 템플릿 렌더링</td>
</tr>
</tbody></table>
<p>비교 요약</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>함수뷰 (FBV)</th>
<th>클래스뷰 (CBV)</th>
<th>제너릭뷰</th>
</tr>
</thead>
<tbody><tr>
<td><strong>구조</strong></td>
<td>함수</td>
<td>클래스</td>
<td>클래스 (CBV 확장)</td>
</tr>
<tr>
<td><strong>코드량</strong></td>
<td>많음</td>
<td>중간</td>
<td>매우 적음</td>
</tr>
<tr>
<td><strong>가독성</strong></td>
<td>직관적</td>
<td>구조적</td>
<td>선언적</td>
</tr>
<tr>
<td><strong>재사용성</strong></td>
<td>낮음</td>
<td>높음</td>
<td>매우 높음</td>
</tr>
<tr>
<td><strong>유연성</strong></td>
<td>매우 높음</td>
<td>높음</td>
<td>낮음 (커스터마이징 필요)</td>
</tr>
<tr>
<td><strong>적합한 경우</strong></td>
<td>단순/특수 로직</td>
<td>복잡한 로직</td>
<td>표준 CRUD</td>
</tr>
</tbody></table>
<p>언제 무엇을 쓸까?</p>
<ul>
<li><strong>FBV</strong> → 로직이 복잡하거나 특수한 경우, 팀원 모두 Django에 익숙하지 않을 때</li>
<li><strong>CBV</strong> → 여러 뷰에서 공통 로직을 공유해야 할 때 (믹스인 활용)</li>
<li><strong>제너릭뷰</strong> → 단순한 CRUD 페이지, 빠른 개발이 필요할 때</li>
</ul>
<blockquote>
<p>실무에서는 세 가지를 <strong>상황에 맞게 혼용</strong>하는 것이 일반적입니다.</p>
</blockquote>
<p> FBV vs CBV vs 제너릭뷰 — CRUD 흐름 비교</p>
<p> CREATE (생성)</p>
<p><strong>FBV</strong></p>
<pre><code class="language-python">def post_create(request):
    if request.method == &#39;POST&#39;:
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect(&#39;post_list&#39;)
    else:
        form = PostForm()
    return render(request, &#39;post_form.html&#39;, {&#39;form&#39;: form})</code></pre>
<p><strong>CBV</strong></p>
<pre><code class="language-python">class PostCreateView(View):
    def get(self, request):
        form = PostForm()
        return render(request, &#39;post_form.html&#39;, {&#39;form&#39;: form})

    def post(self, request):
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()
            return redirect(&#39;post_list&#39;)
        return render(request, &#39;post_form.html&#39;, {&#39;form&#39;: form})</code></pre>
<p><strong>제너릭뷰</strong></p>
<pre><code class="language-python">class PostCreateView(CreateView):
    model = Post
    fields = [&#39;title&#39;, &#39;content&#39;]
    success_url = &#39;/posts/&#39;
    # GET/POST 처리, form 생성, 유효성 검사, 저장, 리다이렉트 → 모두 자동</code></pre>
<p> READ (조회)</p>
<p><strong>FBV</strong></p>
<pre><code class="language-python"># 목록
def post_list(request):
    posts = Post.objects.all()
    return render(request, &#39;post_list.html&#39;, {&#39;posts&#39;: posts})

# 상세
def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, &#39;post_detail.html&#39;, {&#39;post&#39;: post})</code></pre>
<p><strong>CBV</strong></p>
<pre><code class="language-python">class PostListView(View):
    def get(self, request):
        posts = Post.objects.all()
        return render(request, &#39;post_list.html&#39;, {&#39;posts&#39;: posts})

class PostDetailView(View):
    def get(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        return render(request, &#39;post_detail.html&#39;, {&#39;post&#39;: post})</code></pre>
<p><strong>제너릭뷰</strong></p>
<pre><code class="language-python">class PostListView(ListView):
    model = Post
    # Post.objects.all() 자동 실행, &#39;post_list.html&#39; 자동 탐색

class PostDetailView(DetailView):
    model = Post
    # pk로 객체 자동 조회, 없으면 404 자동 처리</code></pre>
<p> UPDATE (수정)</p>
<p><strong>FBV</strong></p>
<pre><code class="language-python">def post_update(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == &#39;POST&#39;:
        form = PostForm(request.POST, instance=post)  # ← instance 직접 넘겨야 함
        if form.is_valid():
            form.save()
            return redirect(&#39;post_detail&#39;, pk=pk)
    else:
        form = PostForm(instance=post)
    return render(request, &#39;post_form.html&#39;, {&#39;form&#39;: form})</code></pre>
<p><strong>CBV</strong></p>
<pre><code class="language-python">class PostUpdateView(View):
    def get(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        form = PostForm(instance=post)
        return render(request, &#39;post_form.html&#39;, {&#39;form&#39;: form})

    def post(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            form.save()
            return redirect(&#39;post_detail&#39;, pk=pk)
        return render(request, &#39;post_form.html&#39;, {&#39;form&#39;: form})</code></pre>
<p><strong>제너릭뷰</strong></p>
<pre><code class="language-python">class PostUpdateView(UpdateView):
    model = Post
    fields = [&#39;title&#39;, &#39;content&#39;]
    success_url = &#39;/posts/&#39;
    # 기존 데이터 자동 바인딩, 유효성 검사, 저장 모두 자동</code></pre>
<p> DELETE (삭제)</p>
<p><strong>FBV</strong></p>
<pre><code class="language-python">def post_delete(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == &#39;POST&#39;:
        post.delete()
        return redirect(&#39;post_list&#39;)
    return render(request, &#39;post_confirm_delete.html&#39;, {&#39;post&#39;: post})</code></pre>
<p><strong>CBV</strong></p>
<pre><code class="language-python">class PostDeleteView(View):
    def get(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        return render(request, &#39;post_confirm_delete.html&#39;, {&#39;post&#39;: post})

    def post(self, request, pk):
        post = get_object_or_404(Post, pk=pk)
        post.delete()
        return redirect(&#39;post_list&#39;)</code></pre>
<p><strong>제너릭뷰</strong></p>
<pre><code class="language-python">class PostDeleteView(DeleteView):
    model = Post
    success_url = &#39;/posts/&#39;
    # 확인 페이지 렌더링 → POST 수신 → 삭제 → 리다이렉트 자동</code></pre>
<p> 흐름 구조 비교 요약</p>
<pre><code>FBV
요청 → if method == &#39;POST&#39; 분기 → 직접 폼/쿼리 처리 → 응답

CBV
요청 → dispatch() → get() / post() 자동 분기 → 처리 → 응답

제너릭뷰
요청 → dispatch() → get_object() / get_form() 자동 실행
     → form_valid() / form_invalid() 자동 분기 → 응답</code></pre><pre><code>
핵심 차이 한 줄 정리

| | 핵심 |
|---|---|
| **FBV** | 모든 흐름을 **내가 직접** 작성 |
| **CBV** | HTTP 메서드 분기를 **Django가** 처리, 나머지는 직접 |
| **제너릭뷰** | CRUD 흐름 전체를 **Django가** 처리, 나는 설정만 |
</code></pre><hr>
<ul>
<li>CRUD ? 생성, 상세 , 수정 , 삭제 각각 어떻게 구현되는지 체득?</li>
</ul>
<pre><code>
Django CRUD 각 기능 역할

1. ModelForm 만들기
```python
# models.py의 필드를 자동으로 HTML 폼으로 변환
class PostForm(ModelForm):
    class Meta:
        model = Post
        fields = [&#39;title&#39;, &#39;content&#39;]</code></pre><blockquote>
<p>DB 모델을 기반으로 <strong>입력 폼을 자동 생성</strong>해주는 역할</p>
</blockquote>
<p>질문 </p>
<p>models.py의 필드를 자동으로 HTML 폼으로 변환 class PostForm(ModelForm): class Meta: model = Post fields = [&#39;title&#39;, &#39;content&#39;] &gt; DB 모델을 기반으로 <strong>입력 폼을 자동 생성</strong>해주는 역할   모델폼은  장고내장 함수인건가?</p>
<p>답변</p>
<p>Django 내장 클래스입니다</p>
<p> 어디서 가져오나요?</p>
<pre><code># Django 내장 모듈에서 import
from django import forms

class PostForm(forms.ModelForm):  # Django가 제공하는 클래스 상속
    class Meta:
        model = Post
        fields = [&#39;title&#39;, &#39;content&#39;]</code></pre><p> ModelForm이 자동으로 해주는 것</p>
<table>
<thead>
<tr>
<th>기능</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>필드 자동 생성</td>
<td>모델의 필드를 자동으로 HTML <code>&lt;input&gt;</code>으로 변환</td>
</tr>
<tr>
<td>유효성 검사</td>
<td>입력값이 올바른지 자동 검증</td>
</tr>
<tr>
<td>DB 저장</td>
<td><code>.save()</code> 한 줄로 DB에 바로 저장</td>
</tr>
</tbody></table>
<p> 직접 만들 때 vs ModelForm 비교</p>
<pre><code class="language-python"># ❌ 직접 만들 때 (길고 복잡)
&lt;input type=&quot;text&quot; name=&quot;title&quot;&gt;
&lt;input type=&quot;text&quot; name=&quot;content&quot;&gt;
# 유효성 검사도 직접 작성...
# DB 저장도 직접 작성...

# ✅ ModelForm 사용 (간단!)
form = PostForm()  # 끝!
form.save()        # DB 저장도 한 줄!</code></pre>
<p> 결론</p>
<pre><code>Django 내장 클래스 ✅
별도 설치 불필요 ✅
from django import forms 로 바로 사용 가능 ✅</code></pre><blockquote>
<p>💡 Django가 반복적인 폼 작업을 <strong>자동화</strong>해주기 위해 만든 강력한 내장 기능입니다!</p>
</blockquote>
<ol start="2">
<li>생성 (Create)<pre><code>사용자가 폼에 데이터 입력 → DB에 새 데이터 저장
예) 게시글 작성, 회원가입</code></pre><blockquote>
<p><strong>새로운 데이터를 추가</strong>하는 기능</p>
</blockquote>
</li>
</ol>
<ol start="3">
<li>상세 (Detail)<pre><code>목록에서 항목 클릭 → 해당 데이터 상세 내용 표시
예) 게시글 본문 보기</code></pre><blockquote>
<p><strong>특정 데이터 하나를 자세히 조회</strong>하는 기능</p>
</blockquote>
</li>
</ol>
<ol start="4">
<li>수정 (Update)<pre><code>기존 데이터를 불러와 폼에 표시 → 수정 후 저장
예) 게시글 편집</code></pre><blockquote>
<p><strong>기존 데이터를 변경</strong>하는 기능</p>
</blockquote>
</li>
</ol>
<ol start="5">
<li>삭제 (Delete)<pre><code>특정 데이터 선택 → DB에서 완전 삭제
예) 게시글 삭제</code></pre><blockquote>
<p><strong>데이터를 DB에서 제거</strong>하는 기능</p>
</blockquote>
</li>
</ol>
<ol start="6">
<li>페이지네이션 (Pagination)<pre><code>데이터가 많을 때 → 한 페이지에 n개씩 나눠서 표시
예) 1페이지, 2페이지, 3페이지...</code></pre><blockquote>
<p><strong>많은 데이터를 나눠서 보여주는</strong> 기능</p>
</blockquote>
</li>
</ol>
<p>전체 흐름 요약</p>
<pre><code>ModelForm        → 입력 폼 자동 생성
Create (생성)    → 데이터 추가 (INSERT)
Detail (상세)    → 데이터 1개 조회 (SELECT)
Update (수정)    → 데이터 변경 (UPDATE)
Delete (삭제)    → 데이터 제거 (DELETE)
Pagination       → 데이터 분할 표시</code></pre><blockquote>
<p>💡 이 6가지가 합쳐지면 <strong>브라우저 기반 CRUD 완성</strong>입니다!</p>
</blockquote>
<pre><code></code></pre><hr>
<p>-클로드 질문 </p>
<p>crud   django 내장 함수 로    form함수가 아닌  modelform 함수를  이용하여  간단하게 만들수있는데  그때  생성 데테일 수정 삭제 기능을 만들수있는데 이 파일의 역할들은 무조건 장고 drf는  crud 기반형태로 만드는게 정석인지 궁금해  추가적으로 페이지네이션과 그외 기능들은 그것도 crud 기반인지?  결국 함수를 알아야하고  클래스를 알아야하고 장고기초를 알아야   전체적인 그림을 볼수있는거니?  각각 파일마다 형식이있는데   템플릿외에는 거의 비슷한 비슷한 구조인지 궁금해</p>
<pre><code>
Django DRF 구조와 CRUD 기반 설계 원리를 종합적으로 검토


 Django / DRF 전체 그림 정리

 1. CRUD가 정석인가?

**YES — 거의 모든 웹 개발의 기반은 CRUD입니다.**
</code></pre><p>C → Create   (생성)
R → Read     (조회/목록/상세)
U → Update   (수정)
D → Delete   (삭제)</p>
<pre><code>
Django든 DRF든 Spring이든 **어떤 프레임워크도 결국 CRUD를 어떻게 편하게 짜느냐**의 싸움입니다.

 2. ModelForm vs DRF Serializer 비교

둘 다 같은 역할, 다른 환경

| | **ModelForm** | **DRF Serializer** |
|--|--|--|
| 용도 | HTML 템플릿 렌더링 | JSON API 응답 |
| 결과물 | 웹 페이지 | JSON 데이터 |
| 사용처 | 일반 Django | DRF (REST API) |
| 역할 | 모델 ↔ HTML Form | 모델 ↔ JSON |

&gt; **구조는 똑같습니다.** ModelForm → Serializer로 이름만 바뀐 느낌
 3. 파일별 역할 구조
</code></pre><p>myapp/
├── models.py        # DB 테이블 정의 (데이터 구조)
├── serializers.py   # 데이터 변환 (모델 ↔ JSON)
├── views.py         # 비즈니스 로직 (CRUD 처리)
├── urls.py          # URL 라우팅 (어떤 URL → 어떤 뷰)
├── admin.py         # 관리자 페이지 등록
└── templates/       # HTML (DRF에선 거의 안 씀)</p>
<pre><code>
**템플릿 빼고는 구조가 거의 동일합니다** — 맞게 보셨어요 ✅

4. 페이지네이션도 CRUD 기반인가?

**YES — R(Read/조회)의 확장입니다.**
</code></pre><p>기본 조회     → 전체 데이터 반환
페이지네이션  → 조회 + 잘라서 반환
검색/필터     → 조회 + 조건 추가
정렬          → 조회 + 순서 지정</p>
<pre><code>
&gt; 페이지네이션, 검색, 필터, 정렬 전부 **Read의 옵션**이에요

DRF에서는 설정 몇 줄로 자동 적용됩니다:
```python
# settings.py
REST_FRAMEWORK = {
    &#39;DEFAULT_PAGINATION_CLASS&#39;: &#39;rest_framework.pagination.PageNumberPagination&#39;,
    &#39;PAGE_SIZE&#39;: 10
}</code></pre><ol start="5">
<li>함수형 vs 클래스형 뷰</li>
</ol>
<p>Django/DRF는 두 가지 방식 모두 지원:</p>
<pre><code class="language-python"># 함수형 (FBV) - 직관적, 초보자 친화적
@api_view([&#39;GET&#39;, &#39;POST&#39;])
def post_list(request):
    if request.method == &#39;GET&#39;:
        posts = Post.objects.all()
        serializer = PostSerializer(posts, many=True)
        return Response(serializer.data)

# 클래스형 (CBV) - 간결, 재사용성 높음
class PostListView(generics.ListCreateAPIView):
    queryset = Post.objects.all()
    serializer_class = PostSerializer</code></pre>
<p><strong>클래스형이 더 적은 코드로 CRUD 전체를 커버합니다:</strong></p>
<pre><code class="language-python"># 이 한 클래스가 List + Create를 자동으로 처리
class PostListView(generics.ListCreateAPIView): ...

# 이 한 클래스가 Detail + Update + Delete를 자동으로 처리
class PostDetailView(generics.RetrieveUpdateDestroyAPIView): ...</code></pre>
<ol start="6">
<li>전체 흐름 한눈에</li>
</ol>
<pre><code>요청(Request)
    ↓
urls.py       → &quot;이 URL은 이 뷰로 보내&quot;
    ↓
views.py      → &quot;CRUD 중 어떤 작업인지 판단&quot;
    ↓
serializers.py → &quot;데이터 유효성 검사 + 변환&quot;
    ↓
models.py     → &quot;DB에서 읽기/쓰기&quot;
    ↓
응답(Response) → JSON 반환</code></pre><ol start="7">
<li>결론 — 공부 순서</li>
</ol>
<pre><code>Python 기초 (함수, 클래스)
    ↓
Django 기초 (MTV 구조, ORM)
    ↓
CRUD 완성 (ModelForm 또는 Serializer)
    ↓
DRF (API 형태로 전환)
    ↓
심화 (페이지네이션, 인증, 필터, 권한)


&gt; **맞습니다 — 함수 → 클래스 → Django 기초를 알아야 전체 그림이 보입니다.**
&gt; 각 파일은 역할만 다를 뿐 **비슷한 패턴이 반복**되기 때문에, 하나를 제대로 이해하면 나머지는 빠르게 익혀집니다. 💡
</code></pre><hr>
<h1 id="클로드-질문">클로드 질문</h1>
<p>Django든 DRF든 Spring이든 어떤 프레임워크도 결국 CRUD를 어떻게 편하게 짜느냐의 싸움이라고 했는데  백엔드에서  종류는?</p>
<hr>
<pre><code>아니요, 훨씬 더 많습니다! Django/DRF/Spring은 대표적인 예시일 뿐이고, 백엔드 프레임워크는 언어별로 굉장히 다양해요.전혀요! 저 3개는 &quot;한국에서 많이 쓰는 것들&quot; 중 일부일 뿐입니다.

언어별로 각자 대표 프레임워크들이 있어요:**

 **Python** — Django(+DRF), FastAPI, Flask
 **JVM (Java/Kotlin)** — Spring Boot, Quarkus, Ktor, Micronaut
**Node.js (JS/TS)** — Express, NestJS, Fastify, Hono
**Ruby** — Ruby on Rails (CoC 원칙으로 CRUD 속도가 가장 빠름)
**PHP** — Laravel
**Go** — Gin, Echo, Fiber
**Rust** — Actix Web, Axum
**C#** — ASP.NET Core


&quot;CRUD 싸움&quot;이라는 말의 핵심**은 이거예요.

아무리 기술 스택이 달라도, 99%의 웹 백엔드는 결국 이 파이프라인입니다:

&gt; **요청 받기 → 인증/파싱 → DB 읽고/쓰고 → 응답 반환**

프레임워크마다 이걸 얼마나 *편하게*, *안전하게*, *빠르게* 만드느냐의 차이인 거죠.

한국에서 저 3개(Django, DRF, Spring)가 특히 많이 언급되는 이유**는 부트캠프 커리큘럼과 대기업(특히 Spring)의 영향이 큽니다. 실리콘밸리 스타트업에서는 Node.js + Express, 혹은 Go + Gin이 훨씬 흔해요.
</code></pre><hr>
<p><a href="https://velog.io/@hy_1023/Django-%EA%B8%B0%EC%B4%88-%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B01-%EC%84%B8%EB%B2%88%EC%A7%B8-%ED%97%B7%EA%B0%88%EB%A6%AC%EB%8A%94-%EB%B6%80%EB%B6%84"><a href="https://velog.io/@hy_1023/Django-%EA%B8%B0%EC%B4%88-%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B02">https://velog.io/@hy_1023/Django-%EA%B8%B0%EC%B4%88-%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B01-%EC%84%B8%EB%B2%88%EC%A7%B8-%ED%97%B7%EA%B0%88%EB%A6%AC%EB%8A%94-%EB%B6%80%EB%B6%84</a></a></p>
<p><a href="https://velog.io/write?id=617a830c-7207-4d35-a346-1ebdbe9440f6">https://velog.io/write?id=617a830c-7207-4d35-a346-1ebdbe9440f6</a></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/f4cc0ace-da22-4616-991b-976cbd250909/image.png" alt=""></p>
<hr>
<h2 id="함수형-view-기초부터">함수형 View 기초부터</h2>
<hr>
<h3 id="🔤-먼저-함수가-뭔지부터">🔤 먼저 &quot;함수&quot;가 뭔지부터</h3>
<pre><code class="language-python"># 함수의 기본 구조
def 함수이름(입력값):
    무언가 처리
    return 결과값</code></pre>
<p>예시</p>
<pre><code class="language-python">def 더하기(a, b):
    result = a + b
    return result</code></pre>
<blockquote>
<p>입력값 받아서 → 처리하고 → 결과 돌려주는 것</p>
</blockquote>
<hr>
<h3 id="🔤-함수형-view는">🔤 함수형 View는?</h3>
<p>View도 똑같이 <strong>함수</strong>예요
단지 입력값이 <strong>request (요청)</strong> 이고
결과값이 <strong>response (응답)</strong> 인 것뿐</p>
<pre><code class="language-python">def study_list(request):   ← 요청을 입력값으로 받고
    처리
    return response        ← 응답을 결과값으로 돌려줌</code></pre>
<hr>
<h3 id="🔄-request--response-가-뭔지">🔄 request / response 가 뭔지</h3>
<pre><code>사용자가 브라우저에서 주소 입력
        ↓
request (요청) 발생
&quot;나 이 페이지 보고싶어!&quot;

        ↓ View가 받아서 처리

response (응답) 반환
&quot;여기 HTML 페이지 줄게!&quot;
        ↓
브라우저에 화면 출력</code></pre><hr>
<h3 id="👀-실제-함수형-view-코드">👀 실제 함수형 View 코드</h3>
<pre><code class="language-python">def study_list(request):        # 1. 요청 받음

    studies = Study.objects.all()  # 2. DB에서 데이터 꺼냄

    return render(               # 3. 응답 돌려줌
        request,
        &#39;list.html&#39;,             # 4. 이 Template을 사용해서
        {&#39;studies&#39;: studies}     # 5. 이 데이터와 함께
    )</code></pre>
<p>단계별로 보면</p>
<pre><code>1단계  사용자가 /study/ 접속
2단계  View가 요청 받음
3단계  DB에서 공부 기록 전부 꺼냄
4단계  list.html 에 데이터 넘김
5단계  완성된 HTML을 브라우저에 돌려줌</code></pre><hr>
<h3 id="🆚-클래스형-view랑-비교">🆚 클래스형 View랑 비교</h3>
<pre><code class="language-python"># 함수형 View
# 모든 과정이 눈에 보임
def study_list(request):
    studies = Study.objects.all()   ← 직접 씀
    return render(request, &#39;list.html&#39;, {&#39;studies&#39;: studies})  ← 직접 씀


# 클래스형 View
# 내부 과정이 숨겨져 있음
class StudyListView(ListView):
    model = Study                   ← 이것만 써도
    template_name = &#39;list.html&#39;     ← 위에꺼 자동으로 해줌</code></pre>
<hr>
<h3 id="✅-한-줄-정리">✅ 한 줄 정리</h3>
<pre><code>함수형 View
= 요청(request)을 받아서
  DB 처리하고
  응답(response)을 돌려주는
  일반 Python 함수</code></pre><blockquote>
<p>특별한 게 아니라
입출력이 request/response인 <strong>그냥 함수</strong>예요 😊</p>
</blockquote>
<hr>
<h2 id="이-교안-내용-설명">이 교안 내용 설명</h2>
<p>전체 흐름을 쉽게 풀어드릴게요.</p>
<hr>
<h3 id="📌-이번-교안의-목표-3가지">📌 이번 교안의 목표 3가지</h3>
<table>
<thead>
<tr>
<th>목표</th>
<th>쉽게 말하면</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Django 구조 익히기</strong></td>
<td>Django가 어떤 파일들로 이루어져 있는지 파악하기</td>
</tr>
<tr>
<td><strong>데이터 흐름 익히기</strong></td>
<td>모델(DB 설계) → DB 저장 → admin 확인까지의 과정</td>
</tr>
<tr>
<td><strong>화면 출력 익히기</strong></td>
<td>DB 데이터를 꺼내서 HTML로 브라우저에 보여주기</td>
</tr>
</tbody></table>
<hr>
<h3 id="🔴-빨간-박스-부분-설명">🔴 빨간 박스 부분 설명</h3>
<blockquote>
<p>*&quot;이 흐름이 이해되면 Form / CRUD / Pagination / DRF도 훨씬 덜 어렵게 느껴집니다&quot;*</p>
</blockquote>
<p>이 말은 이런 뜻이에요:</p>
<ul>
<li><strong>Form</strong> → 사용자 입력 처리</li>
<li><strong>CRUD</strong> → 데이터 생성/조회/수정/삭제</li>
<li><strong>Pagination</strong> → 목록을 여러 페이지로 나누기</li>
<li><strong>DRF</strong> → Django REST Framework (API 만들기)</li>
</ul>
<p>이것들이 나중에 배울 더 어려운 개념들인데, <strong>지금 배우는 &quot;데이터 → View → Template → 브라우저&quot; 흐름</strong>을 제대로 이해하면, 나중 개념들도 결국 이 흐름의 확장이라 훨씬 쉽게 느껴진다는 뜻입니다.</p>
<p>즉, <strong>지금 이 흐름을 탄탄히 잡는 게 Django 전체의 기초</strong>라는 말이에요! 어느 부분이 특히 헷갈리세요?</p>
<hr>
<h2 id="django-rest-framework-drf-란">Django REST Framework (DRF) 란?</h2>
<hr>
<h3 id="🌐-먼저-api가-뭔지부터">🌐 먼저 &quot;API&quot;가 뭔지부터</h3>
<p>예를 들어, 카카오 지도 앱을 생각해보세요.</p>
<pre><code>[내 앱] ──── &quot;서울 맛집 좌표 줘!&quot; ───→ [카카오 서버]
[내 앱] ←─── &quot;위도: 37.5, 경도: 126.9&quot; ── [카카오 서버]</code></pre><p>이렇게 <strong>서버에 데이터를 요청하고 받아오는 창구</strong>가 바로 <strong>API</strong>입니다.
데이터는 보통 <strong>JSON 형식</strong>으로 주고받아요.</p>
<hr>
<h3 id="🔄-일반-django-vs-drf-차이">🔄 일반 Django vs DRF 차이</h3>
<table>
<thead>
<tr>
<th></th>
<th>일반 Django</th>
<th>DRF</th>
</tr>
</thead>
<tbody><tr>
<td><strong>응답 형식</strong></td>
<td>HTML 페이지</td>
<td>JSON 데이터</td>
</tr>
<tr>
<td><strong>사용 대상</strong></td>
<td>브라우저</td>
<td>앱, 프론트엔드, 다른 서버</td>
</tr>
<tr>
<td><strong>예시</strong></td>
<td>블로그 웹사이트</td>
<td>카카오 API, 네이버 API</td>
</tr>
</tbody></table>
<hr>
<h3 id="📦-실제-예시로-보면">📦 실제 예시로 보면</h3>
<p><strong>일반 Django</strong> (HTML 반환)</p>
<pre><code>브라우저가 /posts/ 요청
→ Django가 예쁜 HTML 페이지로 응답</code></pre><p><strong>DRF</strong> (JSON 반환)</p>
<pre><code>앱/프론트가 /api/posts/ 요청
→ DRF가 JSON 데이터로 응답

{
  &quot;id&quot;: 1,
  &quot;title&quot;: &quot;오늘 공부&quot;,
  &quot;time&quot;: 120
}</code></pre><hr>
<h3 id="🏗️-drf의-핵심-구조">🏗️ DRF의 핵심 구조</h3>
<pre><code>DB 데이터
  ↓
Serializer  ← DRF의 핵심! (DB 데이터를 JSON으로 변환)
  ↓
API View    ← 요청을 받아서 처리
  ↓
JSON 응답   ← 앱/프론트엔드로 전달</code></pre><blockquote>
<p>일반 Django에서 <strong>Template</strong>이 하던 역할을,
DRF에서는 <strong>Serializer</strong>가 대신한다고 보면 돼요!</p>
</blockquote>
<hr>
<h3 id="🎯-왜-지금-배우는-흐름이-중요하냐면">🎯 왜 지금 배우는 흐름이 중요하냐면</h3>
<pre><code>일반 Django:  DB → View → Template → HTML
DRF:          DB → View → Serializer → JSON</code></pre><p>구조가 거의 똑같아요! <strong>Template 자리에 Serializer가 들어간 것</strong>뿐이라,
지금 흐름을 잘 이해하면 DRF도 자연스럽게 이해되는 거예요 😊</p>
<p>지금 단계에서는 DRF를 바로 쓸 필요는 없고, <strong>&quot;나중에 이런 게 있구나&quot;</strong> 정도로만 알아두시면 충분해요! 더 궁금한 부분 있으세요?</p>
<hr>
<h2 id="거의-맞아요-조금만-더-정확하게-잡아드릴게요">거의 맞아요! 조금만 더 정확하게 잡아드릴게요</h2>
<hr>
<h3 id="일반-django-view가-하는-역할들">일반 Django View가 하는 역할들</h3>
<pre><code>def my_view(request):
    1. 요청 처리 (GET인지 POST인지 확인)
    2. DB에서 데이터 조회 (Model)
    3. 비즈니스 로직 처리
    4. 데이터를 Template에 넘기기
    5. HTML 응답 반환</code></pre><hr>
<h3 id="drf에서-역할-분담">DRF에서 역할 분담</h3>
<pre><code>View         → 1. 요청 처리
               2. DB 데이터 조회
               3. 비즈니스 로직 처리
               4. Serializer에 데이터 넘기기

Serializer   → 5. DB 데이터를 JSON으로 변환   ← 이 부분만 가져간 것
               +  들어온 JSON 데이터 유효성 검사 (보너스 역할)

View         → 6. JSON 응답 반환</code></pre><hr>
<h3 id="정리하면">정리하면</h3>
<blockquote>
<p>✅ 맞아요! <strong>Serializer는 View의 역할 중 &quot;데이터 변환/포맷팅&quot; 부분만 담당</strong>하는 거예요.</p>
</blockquote>
<p>일반 Django로 치면 <strong>Template이 HTML로 포맷팅</strong>하던 걸,
DRF에서는 <strong>Serializer가 JSON으로 포맷팅</strong>하는 거라고 보면 정확합니다.</p>
<p><strong>View는 여전히 핵심 역할</strong>을 하고, Serializer는 그 중 한 파트를 전담하는 분업 구조예요 😊</p>
<hr>
<h2 id="정확합니다-아주-잘-파악하셨어요-👍">정확합니다! 아주 잘 파악하셨어요 👍</h2>
<hr>
<h3 id="drf의-큰-흐름">DRF의 큰 흐름</h3>
<pre><code>[요청 들어올 때]
클라이언트 요청
    ↓
  View (1번째) ← 요청 받기, 어떤 데이터 꺼낼지 결정
    ↓
  Serializer   ← DB 데이터를 JSON으로 변환
    ↓
  View (2번째) ← JSON을 응답으로 반환
    ↓
클라이언트에 JSON 전달</code></pre><hr>
<h3 id="일반-django랑-비교하면">일반 Django랑 비교하면</h3>
<pre><code>일반 Django:
클라이언트 → View(1번째) → Template → View(2번째) → 클라이언트

DRF:
클라이언트 → View(1번째) → Serializer → View(2번째) → 클라이언트</code></pre><p><strong>Template 자리에 Serializer가 들어간 것</strong>뿐이고,
View가 앞뒤로 두 번 역할 한다는 구조는 <strong>완전히 동일</strong>해요!</p>
<hr>
<h3 id="한-줄-요약">한 줄 요약</h3>
<blockquote>
<p><strong>View = 교통정리</strong> (앞에서 받고, 뒤에서 내보내고)
<strong>Serializer / Template = 중간 변환기</strong> (데이터를 원하는 형태로 바꾸기)</p>
</blockquote>
<p>이 큰 그림을 잡으셨으면 DRF 배울 때 훨씬 수월할 거예요 😊</p>
<hr>
<h1 id="django-rest-framework-drf-에서">Django REST Framework (DRF) 에서..</h1>
<h2 id="rest--framework-단어-의미">REST / Framework 단어 의미</h2>
<hr>
<h3 id="🔤-rest">🔤 REST</h3>
<p><strong>Representational State Transfer</strong> 의 약자인데, 단어보단 개념으로 이해하는게 편해요.</p>
<blockquote>
<p><strong>&quot;URL로 자원을 표현하고, HTTP 방식으로 행동을 표현한다&quot;</strong></p>
</blockquote>
<p>예시로 보면</p>
<pre><code>GET    /api/posts/      → 게시글 목록 조회
POST   /api/posts/      → 게시글 생성
GET    /api/posts/1/    → 1번 게시글 조회
PUT    /api/posts/1/    → 1번 게시글 수정
DELETE /api/posts/1/    → 1번 게시글 삭제</code></pre><p>URL은 <strong>&quot;무엇을&quot;</strong>, GET/POST/DELETE는 <strong>&quot;어떻게&quot;</strong> 를 나타내는 규칙이에요.
즉 REST는 <strong>API를 만들 때 지키는 설계 규칙/약속</strong> 이라고 보면 돼요.</p>
<hr>
<h3 id="🔤-framework">🔤 Framework</h3>
<blockquote>
<p><strong>&quot;자주 쓰는 기능들을 미리 만들어 놓은 틀&quot;</strong></p>
</blockquote>
<p>요리로 비유하면</p>
<pre><code>Framework 없이  →  칼, 도마, 냄비 직접 다 만들어서 요리
Framework 있으면 →  주방 도구 다 갖춰진 주방에서 요리만 집중</code></pre><p>Django 자체도 Framework예요.
로그인, DB연결, URL 라우팅 등을 <strong>직접 처음부터 안 만들어도 되게</strong> 미리 준비해둔 것이죠.</p>
<hr>
<h3 id="🔤-정리">🔤 정리</h3>
<table>
<thead>
<tr>
<th>단어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><strong>REST</strong></td>
<td>API 설계 규칙/약속</td>
</tr>
<tr>
<td><strong>Framework</strong></td>
<td>미리 만들어놓은 편의 도구 모음</td>
</tr>
<tr>
<td><strong>DRF</strong></td>
<td>REST 규칙을 따르는 API를 쉽게 만들 수 있게 도와주는 도구 모음</td>
</tr>
</tbody></table>
<hr>
<h2 id="url-라우팅이란">URL 라우팅이란?</h2>
<hr>
<h3 id="🔤-라우팅--길-안내">🔤 라우팅 = &quot;길 안내&quot;</h3>
<blockquote>
<p><strong>&quot;이 URL로 요청이 들어오면, 어느 View로 보내줄지 결정하는 것&quot;</strong></p>
</blockquote>
<p>실생활 비유로 보면</p>
<pre><code>음식점 입구 직원 = 라우터

&quot;혼자 오셨어요?&quot; → 1번 테이블로 안내
&quot;2명이요&quot;        → 2번 테이블로 안내
&quot;포장이요&quot;       → 포장 카운터로 안내</code></pre><hr>
<h3 id="🔤-django에서-실제로-보면">🔤 Django에서 실제로 보면</h3>
<p>Django는 <code>urls.py</code> 파일에서 라우팅을 담당해요</p>
<pre><code class="language-python"># urls.py

urlpatterns = [
    /posts/    →  posts_view 함수로 보내줘
    /login/    →  login_view 함수로 보내줘
    /admin/    →  admin 페이지로 보내줘
]</code></pre>
<hr>
<h3 id="🔤-전체-흐름">🔤 전체 흐름</h3>
<pre><code>사용자가 브라우저에 URL 입력
        ↓
  /posts/ 로 요청이 들어옴
        ↓
  urls.py 가 확인  ← 라우팅이 일어나는 곳
        ↓
  &quot;posts_view 로 가!&quot; 
        ↓
  View 가 처리 시작</code></pre><hr>
<h3 id="🔤-라우팅이-없다면">🔤 라우팅이 없다면?</h3>
<pre><code>요청이 들어왔는데
어느 View로 보내야 할지 몰라서
그냥 멈춰버림 😵</code></pre><p>즉 라우팅은 <strong>요청을 올바른 View로 연결해주는 교통정리</strong> 역할이에요!</p>
<p>Framework가 이걸 미리 만들어놨기 때문에 우리는 <code>urls.py</code> 에 규칙만 적어주면 되는 거예요 😊</p>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/85bebac5-eff5-4df7-ba15-76ef3ca2513f/image.png" alt=""></p>
<h2 id="전체-실습-흐름-설명">전체 실습 흐름 설명</h2>
<p>큰 덩어리로 나눠서 설명할게요!</p>
<hr>
<h3 id="📦-1단계--환경-준비-14번">📦 1단계 : 환경 준비 (1~4번)</h3>
<pre><code>1. Python 설치 확인    → Django는 Python으로 돌아가니까 먼저 확인
2. 프로젝트 폴더 만들기 → 작업할 공간 생성
3. 가상환경 생성        → 이 프로젝트만의 독립된 환경 만들기
4. Django 설치         → 가상환경 안에 Django 설치</code></pre><blockquote>
<p>가상환경 = 프로젝트마다 별도의 방을 만드는 것
(A프로젝트 Django 3.0, B프로젝트 Django 5.0 따로 관리 가능)</p>
</blockquote>
<hr>
<h3 id="🏗️-2단계--django-프로젝트앱-생성-58번-🔴">🏗️ 2단계 : Django 프로젝트/앱 생성 (5~8번) 🔴</h3>
<pre><code>5. Django 프로젝트 생성  → 집 전체 뼈대 만들기
6. 서버 실행 확인        → 뼈대가 잘 만들어졌는지 확인
7. study 앱 생성        → 집 안에 &quot;공부방&quot; 만들기
8. settings.py 등록     → &quot;나 study 앱 만들었어!&quot; 라고 Django에 알리기</code></pre><blockquote>
<p>프로젝트 = 집 전체
앱 = 집 안의 각 방 (공부방, 거실, 주방...)</p>
</blockquote>
<hr>
<h3 id="📁-3단계--폴더모델-준비-910번-🔴">📁 3단계 : 폴더/모델 준비 (9~10번) 🔴</h3>
<pre><code>9. templates/static 폴더 준비 → HTML파일, CSS파일 저장할 폴더 만들기
10. Study 모델 작성            → DB 설계 (어떤 데이터를 저장할지)</code></pre><pre><code class="language-python"># 모델 예시
class Study(Model):
    title = 제목
    time  = 공부시간
    date  = 날짜</code></pre>
<hr>
<h3 id="🗄️-4단계--db-반영--admin-1114번">🗄️ 4단계 : DB 반영 &amp; admin (11~14번)</h3>
<pre><code>11. 마이그레이션  → 모델을 실제 DB에 반영
12. admin 등록   → admin 페이지에서 Study 모델 관리할 수 있게 등록
13. 관리자 계정 생성      → admin 페이지 로그인 계정 만들기
14. 관리자 페이지에서 데이터 확인 → DB에 데이터 잘 저장되는지 확인</code></pre><hr>
<h3 id="🔀-5단계--url-연결-1518번-🔴">🔀 5단계 : URL 연결 (15~18번) 🔴</h3>
<pre><code>15. URL 구조 설계        → 어떤 URL을 만들지 계획
16. 프로젝트 urls.py 연결 → 집 대문에서 공부방으로 길 연결
17. 앱 urls.py 연결      → 공부방 안에서 세부 길 연결
18. 임시 View로 URL 확인  → URL이 View까지 잘 연결되는지 테스트</code></pre><pre><code>브라우저 요청
    ↓
프로젝트 urls.py  (대문)
    ↓
앱 urls.py       (공부방 문)
    ↓
View             (목적지)</code></pre><hr>
<h3 id="🎨-6단계--화면-만들기-1922번-🔴">🎨 6단계 : 화면 만들기 (19~22번) 🔴</h3>
<pre><code>19. base.html 작성          → 모든 페이지 공통 틀 만들기 (헤더, 푸터 등)
20. CSS 작성                → 페이지 꾸미기
21. 함수형 View로 목록페이지 구현 → DB 데이터 꺼내서 Template에 전달
22. 브라우저에서 최종 확인       → 완성된 페이지 확인</code></pre><hr>
<h2 id="함수형-view란">함수형 View란?</h2>
<hr>
<h3 id="🔤-먼저-view가-하는-일-복습">🔤 먼저 View가 하는 일 복습</h3>
<pre><code>요청 들어옴 → View가 처리 → 응답 돌려줌</code></pre><p>이 View를 <strong>어떤 방식으로 작성하느냐</strong>에 따라 두 가지로 나뉘어요</p>
<hr>
<h3 id="📦-view의-두-가지-종류">📦 View의 두 가지 종류</h3>
<p><strong>함수형 View (FBV)</strong></p>
<pre><code class="language-python"># 함수로 작성
def study_list(request):       ← 그냥 함수
    studies = Study.objects.all()
    return render(request, &#39;list.html&#39;, {&#39;studies&#39;: studies})</code></pre>
<p><strong>클래스형 View (CBV)</strong></p>
<pre><code class="language-python"># 클래스로 작성
class StudyListView(ListView):  ← 클래스
    model = Study
    template_name = &#39;list.html&#39;</code></pre>
<hr>
<h3 id="🔍-둘의-차이">🔍 둘의 차이</h3>
<pre><code>함수형 View
→ 내가 처음부터 끝까지 직접 코드 작성
→ 코드가 눈에 다 보임
→ 초보자가 이해하기 쉬움
→ 자유도가 높음

클래스형 View
→ Django가 미리 만들어놓은 클래스를 가져다 씀
→ 코드가 매우 짧아짐
→ 내부 동작이 숨겨져 있음
→ 익숙해지면 생산성이 높음</code></pre><hr>
<h3 id="🏠-비유로-보면">🏠 비유로 보면</h3>
<pre><code>함수형 View
= 요리 처음부터 끝까지 직접 하기
  재료 손질 → 볶기 → 간 맞추기 → 담기
  모든 과정이 내 눈에 보임

클래스형 View
= 밀키트 사용하기
  Django가 이미 만들어놓은 틀에
  재료(모델, 템플릿)만 넣으면 완성
  내부 과정은 안 보임</code></pre><hr>
<h3 id="👀-실제-코드-비교">👀 실제 코드 비교</h3>
<p>똑같은 목록 페이지를 만들 때</p>
<p><strong>함수형 View</strong></p>
<pre><code class="language-python">def study_list(request):
    studies = Study.objects.all()  ← DB에서 데이터 꺼내고
    return render(request,          ← Template에 전달하고
        &#39;list.html&#39;, 
        {&#39;studies&#39;: studies})       ← 응답 반환</code></pre>
<p><strong>클래스형 View</strong></p>
<pre><code class="language-python">class StudyListView(ListView):
    model = Study               ← 이것만 써도
    template_name = &#39;list.html&#39; ← 위에꺼 전부 자동으로 해줌</code></pre>
<blockquote>
<p>클래스형은 코드가 짧지만
내부에서 무슨 일이 일어나는지 안 보이죠</p>
</blockquote>
<hr>
<h1 id="질문">질문</h1>
<ol start="21">
<li>함수형 View로 목록페이지 구현 → DB 데이터 꺼내서 Template에 전달
이때 함수형 view는 무엇이고 원래는 어떤걸로 구성되어있는지  큰틀에서 기초적인 부분까지 알려줘</li>
</ol>
<h3 id="🎯-그래서-왜-이번-교안이-함수형으로-시작하냐면">🎯 그래서 왜 이번 교안이 함수형으로 시작하냐면</h3>
<pre><code>함수형 View로 먼저 배우는 이유

DB에서 데이터 꺼내는 과정     ← 눈에 보임
Template에 전달하는 과정      ← 눈에 보임
응답 반환하는 과정            ← 눈에 보임

이 흐름을 직접 눈으로 보면서 익혀야
나중에 클래스형 View도 이해가 되기 때문!</code></pre><hr>
<h3 id="✅-한-줄-정리-1">✅ 한 줄 정리</h3>
<pre><code>함수형 View = 모든 과정을 직접 함수로 작성 (초보자용, 흐름 파악에 좋음)
클래스형 View = Django 내장 클래스 활용 (코드 짧음, 흐름이 숨겨져 있음)

함수형 먼저 익히고 → 클래스형으로 넘어가는 게 정석 순서!</code></pre><hr>
<h3 id="🔴-전체-흐름-한눈에">🔴 전체 흐름 한눈에</h3>
<pre><code>환경준비 → 프로젝트/앱 생성 → 모델(DB설계) → URL연결 → 화면출력</code></pre><p>이게 Django 프로젝트를 만드는 <strong>기본 패턴</strong>이고, 앞으로 어떤 프로젝트를 만들어도 이 순서가 반복돼요!</p>
<p>어느 단계가 특히 헷갈리세요? 😊</p>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/7498a29c-8af3-41c5-b4de-7af1f871b26f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/892078cf-bbe5-437f-bb41-698eb104e3c0/image.png" alt="">
<img src="https://velog.velcdn.com/images/hy_1023/post/eea588fc-a7f3-4e2d-ad38-25aae11934e8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/a16ed2aa-3f0c-497a-801c-14e580709782/image.png" alt=""></p>
<h2 id="데이터-구조-설계란">데이터 구조 설계란?</h2>
<hr>
<h3 id="🤔-왜-화면보다-데이터를-먼저-생각해야-하나">🤔 왜 화면보다 데이터를 먼저 생각해야 하나?</h3>
<pre><code>❌ 잘못된 사고 흐름
&quot;목록 페이지 만들어야지&quot; → &quot;그럼 뭘 보여주지?&quot; → &quot;아 제목이랑 날짜?&quot; 
→ 나중에 시간도 보여주고 싶은데... 다시 설계 😵

✅ 올바른 사고 흐름
&quot;무슨 데이터를 저장할까?&quot; 먼저 결정
→ 그 다음 화면 설계
→ 나중에 뒤집을 일이 없음 😊</code></pre><hr>
<h3 id="📋-실제-설계-과정">📋 실제 설계 과정</h3>
<p><strong>Step 1. 서비스 목적 파악</strong></p>
<pre><code>&quot;공부시간 기록기&quot;
→ 사용자가 공부한 내용을 기록하는 서비스</code></pre><p><strong>Step 2. 어떤 정보가 필요한지 나열</strong></p>
<pre><code>공부를 기록하려면 뭐가 필요할까?
- 무슨 공부를 했는지   → title
- 어떤 분야인지        → category
- 언제 했는지          → study_date
- 얼마나 했는지        → hours, minutes
- 메모할 내용          → memo
- 언제 등록했는지      → created_at (자동)
- 언제 수정했는지      → updated_at (자동)</code></pre><p><strong>Step 3. 각 데이터 타입 결정</strong></p>
<pre><code>title       → 글자     (CharField)
category    → 글자     (CharField)
study_date  → 날짜     (DateField)
hours       → 숫자     (IntegerField)
minutes     → 숫자     (IntegerField)
memo        → 긴 글자  (TextField)
created_at  → 날짜+시간 (DateTimeField)
updated_at  → 날짜+시간 (DateTimeField)</code></pre><hr>
<h3 id="🔗-모델이-정해지면-나머지가-자동으로-정해지는-이유">🔗 모델이 정해지면 나머지가 자동으로 정해지는 이유</h3>
<pre><code>모델 (Study)
    ↓
DB 구조가 정해짐
    → title, category, hours... 컬럼 생성

    ↓
admin 화면이 정해짐
    → 관리자 페이지에서 저 필드들이 보임

    ↓
Form 구조가 정해짐
    → 입력 폼에 저 필드들이 들어감

    ↓
Serializer 구조가 정해짐 (DRF)
    → JSON으로 저 필드들이 나감</code></pre><blockquote>
<p>모델이 <strong>설계도</strong> 역할을 하기 때문에
모델만 잘 짜면 나머지는 그걸 따라가는 구조예요!</p>
</blockquote>
<hr>
<h3 id="🏠-비유로-이해하면">🏠 비유로 이해하면</h3>
<pre><code>집을 지을 때

❌ 잘못된 방식
인테리어 먼저 생각
→ 나중에 방 구조 바꾸려면 벽 다 부숴야 함

✅ 올바른 방식
설계도(구조) 먼저 확정
→ 그 위에 인테리어(화면)를 올림</code></pre><p>Django도 똑같이</p>
<pre><code>❌ 화면 먼저 → 데이터 구조 나중에
✅ 데이터 구조 먼저 → 화면 나중에</code></pre><hr>
<h3 id="✅-한-줄-요약">✅ 한 줄 요약</h3>
<blockquote>
<p><strong>&quot;저장할 데이터가 뭔지 먼저 확정하면, DB/admin/Form/Serializer 전부 그걸 기반으로 자동으로 구조가 잡힌다&quot;</strong></p>
</blockquote>
<p>이게 Django가 <strong>&quot;데이터 중심 프레임워크&quot;</strong> 라고 불리는 이유예요 😊</p>
<hr>
<h3 id="📦-모델--빈-껍데기-생성">📦 모델 = 빈 껍데기 생성</h3>
<p>모델은 그냥 <strong>&quot;이런 형태로 데이터를 저장할거야&quot;</strong> 라고 Python으로 선언하는 것이에요</p>
<pre><code class="language-python"># models.py

class Study(Model):       ← &quot;Study 라는 데이터 틀을 만들겠다&quot;
    title = CharField()   ← &quot;제목이라는 칸을 만들겠다&quot;
    hours = IntegerField() ← &quot;시간이라는 칸을 만들겠다&quot;
    memo  = TextField()   ← &quot;메모라는 칸을 만들겠다&quot;</code></pre>
<blockquote>
<p>이 자체는 그냥 <strong>설계도</strong>예요. 아직 DB에 아무것도 없음!</p>
</blockquote>
<hr>
<h3 id="🗄️-db-컬럼이란">🗄️ DB 컬럼이란?</h3>
<p>모델을 DB에 반영하면 <strong>엑셀 표처럼</strong> 생긴 테이블이 만들어져요</p>
<pre><code>[DB에 생성되는 Study 테이블]

| id | title        | hours | memo          |
|----|--------------|-------|---------------|
| 1  | Django 복습  |   2   | 오늘 열심히   |
| 2  | Python 기초  |   1   | 변수 공부함   |
| 3  | 알고리즘     |   3   | BFS 어렵다    |</code></pre><pre><code>컬럼 = 표의 세로줄 (title, hours, memo...)
행   = 실제 저장된 데이터 1개</code></pre><blockquote>
<p>모델에서 선언한 필드 하나하나가
DB에서는 <strong>컬럼(세로줄)</strong> 이 되는 거예요!</p>
</blockquote>
<hr>
<h3 id="👨💼-관리자-페이지에서-필드란">👨‍💼 관리자 페이지에서 필드란?</h3>
<p>admin 페이지는 <strong>DB를 눈으로 보고 직접 조작할 수 있는 화면</strong>이에요</p>
<pre><code>[admin 페이지에서 데이터 추가할 때]

제목   : [ Django 복습        ]   ← title 필드
시간   : [ 2                  ]   ← hours 필드  
메모   : [ 오늘 열심히 했다   ]   ← memo  필드

                        [저장]</code></pre><blockquote>
<p>모델에서 만든 필드들이
admin 페이지에서 <strong>입력칸</strong>으로 자동으로 나타나는 거예요!</p>
</blockquote>
<hr>
<h3 id="📝-form-구조에-필드가-들어간다는-의미">📝 Form 구조에 필드가 들어간다는 의미</h3>
<p>나중에 일반 사용자도 데이터를 입력할 수 있게
<strong>웹 페이지에 입력 폼</strong>을 만들게 되는데</p>
<pre><code>[일반 사용자가 보는 화면]

공부 기록 추가

제목     : [ Django 복습       ]   ← title 필드
카테고리 : [ Python            ]   ← category 필드
공부시간 : [ 2 ]시간 [ 30 ]분  ← hours, minutes 필드
메모     : [ 오늘 열심히...    ]   ← memo 필드

                        [저장]</code></pre><blockquote>
<p>admin이랑 모양은 똑같지만
<strong>일반 사용자용 페이지</strong>에 만들어지는 입력폼이에요!</p>
</blockquote>
<hr>
<h3 id="🔗-전체-연결-흐름">🔗 전체 연결 흐름</h3>
<pre><code>models.py에서 필드 선언
        ↓
DB      → 컬럼(세로줄)으로 생성
admin   → 입력칸으로 자동 생성
Form    → 사용자용 입력칸으로 생성</code></pre><blockquote>
<p><strong>모델 필드 하나를 선언하면</strong>
DB / admin / Form 에서 <strong>전부 그 필드가 나타나는 것</strong>이에요!</p>
</blockquote>
<hr>
<h3 id="✅-한-줄-요약-1">✅ 한 줄 요약</h3>
<pre><code>모델 필드 = 저장할 데이터의 칸 이름

DB    에서는 → 표의 세로줄 (컬럼)
admin 에서는 → 관리자용 입력칸
Form  에서는 → 사용자용 입력칸</code></pre><p>이게 Django가 편한 이유예요.
모델만 잘 만들면 나머지는 <strong>자동으로 따라오거든요</strong> 😊</p>
<hr>
<p>좋아요, 아주 기초부터 시각적으로 설명할게요!---</p>
<h3 id="📌-각-개념-정리">📌 각 개념 정리</h3>
<p><strong>테이블</strong> = 표 전체</p>
<pre><code>모델 1개 → DB 테이블 1개가 만들어짐
Study 모델 → Study 테이블 생성</code></pre><p><strong>컬럼 (세로줄)</strong> = 모델에서 선언한 필드</p>
<pre><code>title = CharField()   →  title 컬럼 생성
hours = IntegerField() → hours 컬럼 생성</code></pre><p><strong>행 (가로줄)</strong> = 실제 저장된 데이터 1건</p>
<pre><code>공부 기록 1개 입력 → 표에 가로줄 1줄 추가</code></pre><hr>
<h3 id="🔗-모델-→-db-연결-흐름">🔗 모델 → DB 연결 흐름</h3>
<pre><code>models.py 에서 선언
class Study:
    title = CharField()     →  title  컬럼
    hours = IntegerField()  →  hours  컬럼
    memo  = TextField()     →  memo   컬럼

          ↓ 마이그레이션 실행

DB에 Study 테이블 (빈 표) 생성
→ 데이터 저장할 때마다 행이 1줄씩 추가됨</code></pre><blockquote>
<p>마이그레이션 = &quot;내가 설계한 모델을 DB에 실제로 반영해줘!&quot; 라는 명령이에요</p>
</blockquote>
<p>이제 테이블/컬럼/행 개념이 잡히셨나요? 😊</p>
<hr>
<h1 id="질문-1">질문</h1>
<p>컬럼 (세로줄) = 모델에서 선언한 필드 이건 장고 내장메서드??
<strong>메서드는 아니고, Django가 미리 만들어놓은 클래스예요</strong></p>
<hr>
<h3 id="📦-정확한-명칭">📦 정확한 명칭</h3>
<pre><code class="language-python">CharField()      → Django 내장 필드 클래스
IntegerField()   → Django 내장 필드 클래스
TextField()      → Django 내장 필드 클래스
DateField()      → Django 내장 필드 클래스</code></pre>
<blockquote>
<p>이것들을 <strong>&quot;Django 내장 필드 타입&quot;</strong> 이라고 불러요</p>
</blockquote>
<hr>
<h3 id="🔤-메서드-vs-클래스-차이">🔤 메서드 vs 클래스 차이</h3>
<pre><code class="language-python"># 메서드 = 어떤 동작을 수행하는 함수
print()     ← 출력하는 동작
len()       ← 길이를 재는 동작

# 클래스 = 어떤 형태/틀을 정의하는 것
CharField()     ← &quot;이 칸은 글자를 저장하는 칸이야&quot; 라고 정의
IntegerField()  ← &quot;이 칸은 숫자를 저장하는 칸이야&quot; 라고 정의</code></pre>
<hr>
<h3 id="🎯-왜-이런-클래스가-필요하냐면">🎯 왜 이런 클래스가 필요하냐면</h3>
<pre><code class="language-python"># 그냥 이렇게만 쓰면 Django가 모름
title = ???   ← 이게 글자야? 숫자야? 날짜야?

# 필드 타입을 명시해줘야
title = CharField()    ← &quot;글자 저장하는 칸&quot;
hours = IntegerField() ← &quot;숫자 저장하는 칸&quot;</code></pre>
<p>DB에 테이블을 만들 때 각 컬럼이 <strong>어떤 종류의 데이터를 저장할지</strong> 알아야 하기 때문이에요!</p>
<hr>
<h3 id="📋-자주-쓰는-django-내장-필드-타입">📋 자주 쓰는 Django 내장 필드 타입</h3>
<pre><code class="language-python">CharField()       → 짧은 글자  (제목, 이름 등)
TextField()       → 긴 글자    (본문, 메모 등)
IntegerField()    → 정수 숫자  (시간, 나이 등)
DateField()       → 날짜       (2026-03-20)
DateTimeField()   → 날짜+시간  (2026-03-20 14:30)
BooleanField()    → 참/거짓    (완료여부 등)</code></pre>
<blockquote>
<p>이 모든 것들이 <strong>Django가 미리 만들어놓은 내장 필드 클래스</strong>예요.
우리는 그냥 가져다 쓰기만 하면 돼요 😊</p>
</blockquote>
<hr>
<h1 id="질문-2">질문</h1>
<p>형태를 정의하는 건 클래스라고 생각하고  어떤동작을 수행하는 함수는 메서드라고 생각하면 되겠네? 장고 내장함수기반의 ?</p>
<hr>
<h3 id="✅-맞는-부분">✅ 맞는 부분</h3>
<pre><code>클래스  = 형태/틀을 정의하는 것  ← 맞아요
메서드  = 동작을 수행하는 것     ← 맞아요</code></pre><hr>
<h3 id="🔧-딱-한-가지-추가">🔧 딱 한 가지 추가</h3>
<p>메서드는 <strong>독립적으로 존재하는 게 아니라 클래스 안에 있는 함수</strong>예요</p>
<pre><code class="language-python">class Study:              ← 클래스
    title = CharField()   ← 필드 (형태 정의)

    def save():           ← 메서드 (클래스 안에 있는 함수)
    def delete():         ← 메서드</code></pre>
<pre><code>함수  = 독립적으로 존재  →  def my_func():
메서드 = 클래스 안에 존재 →  class 안의 def</code></pre><hr>
<h3 id="🎯-django-내장-필드는">🎯 Django 내장 필드는?</h3>
<pre><code>Django 내장 클래스 기반의 필드 타입</code></pre><blockquote>
<p>&quot;함수기반&quot; 보다는 <strong>&quot;클래스 기반&quot;</strong> 이 더 정확해요!
CharField, IntegerField 전부 Django가 만들어놓은 <strong>클래스</strong>니까요 😊</p>
</blockquote>
<hr>
<h3 id="한-줄-정리">한 줄 정리</h3>
<pre><code>클래스  → 틀/형태 정의
메서드  → 클래스 안에 있는 동작 함수
필드타입 → Django 내장 클래스</code></pre><p>이 구조가 앞으로 Django 코드 읽을 때 계속 나오니까 잘 잡아두셨어요 👍</p>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/b09c99f0-f8ad-496f-9641-0cc055ee63dc/image.png" alt=""></p>
<h2 id="왜-이-순서인가">왜 이 순서인가?</h2>
<p>핵심은 <strong>앞 단계가 없으면 다음 단계가 불가능하다</strong>는 거예요.</p>
<hr>
<h3 id="🔗-의존성-사슬로-보면">🔗 의존성 사슬로 보면</h3>
<pre><code>모델 (설계도)
  ↓ 모델이 있어야
DB 테이블 (실제 저장공간)
  ↓ 테이블이 있어야
admin에서 데이터 입력 가능
  ↓ 데이터가 있어야
목록 페이지에서 보여줄 게 생김
  ↓ URL이 연결되어야
View가 동작함
  ↓ View가 있어야
Template에 데이터를 넘길 수 있음</code></pre><blockquote>
<p>딱 한 단계만 빠져도 다음이 무너지는 구조예요</p>
</blockquote>
<hr>
<h3 id="🏠-집짓기로-비유하면">🏠 집짓기로 비유하면</h3>
<pre><code>1. 설계도 그리기       ← 모델 작성
      ↓ 설계도 없이 집을 못 지음
2. 뼈대/기초 공사      ← DB 테이블 생성 (마이그레이션)
      ↓ 뼈대 없이 내부 공사 못함
3. 내부 확인 (임시)    ← admin에서 데이터 넣어보기
      ↓ 데이터 없이 화면에 보여줄 게 없음
4. 인테리어            ← View + Template으로 화면 구성</code></pre><hr>
<h3 id="❌-순서를-무시하면-생기는-일">❌ 순서를 무시하면 생기는 일</h3>
<pre><code>모델 없이 admin 열면?
→ 보여줄 테이블 자체가 없음

데이터 없이 목록 페이지 만들면?
→ 빈 화면만 나옴
→ 내가 잘 만든건지 틀린건지 확인 불가

URL 연결 없이 View 만들면?
→ View가 있어도 접근할 방법이 없음</code></pre><hr>
<h3 id="✅-한-줄-정리-2">✅ 한 줄 정리</h3>
<pre><code>이 순서는 단순히 보기 좋은 순서가 아니라
앞 단계가 반드시 있어야 다음 단계가 가능한
기술적 의존 관계 순서예요!</code></pre><blockquote>
<p>이 순서 자체가 나중에 <strong>새 프로젝트 만들 때마다 반복하는 패턴</strong>이 돼요 😊</p>
</blockquote>
<hr>
<h2 id="admin은-필수가-아니에요">Admin은 필수가 아니에요!</h2>
<hr>
<h3 id="🎯-admin의-정체">🎯 Admin의 정체</h3>
<pre><code>Admin = Django가 기본으로 제공하는 
        데이터 관리용 도구 (관리자 페이지)</code></pre><hr>
<h3 id="🔄-이번-교안에서-admin을-쓰는-이유">🔄 이번 교안에서 Admin을 쓰는 이유</h3>
<pre><code>지금 상황
→ 아직 사용자가 데이터 입력하는 화면(Form)을 안 만들었음
→ 그런데 목록 페이지를 테스트하려면 데이터가 필요함

그래서 Admin을 임시로 사용
→ &quot;일단 여기서 데이터 넣어놓고 테스트하자!&quot;</code></pre><blockquote>
<p>Admin이 필수라서가 아니라
<strong>지금 단계에서 데이터 넣을 방법이 Admin뿐이라서</strong> 쓰는 거예요</p>
</blockquote>
<hr>
<h3 id="📋-실제-서비스에서는">📋 실제 서비스에서는</h3>
<pre><code>일반 사용자    →  Form 페이지에서 데이터 입력
관리자         →  Admin 페이지에서 데이터 관리

즉 Admin은 관리자 전용 도구일 뿐
필수 기능이 아님!</code></pre><hr>
<h3 id="✅-정리">✅ 정리</h3>
<pre><code>지금 교안에서 Admin 쓰는 이유
= Form이 아직 없으니까 임시로 데이터 넣는 용도

나중에 Form 만들면
= 일반 사용자는 Form으로 입력
= Admin은 있어도 되고 없어도 됨</code></pre><blockquote>
<p>나중에 배울 <strong>CRUD / Form</strong> 단계가 되면
Admin 없이도 데이터를 다룰 수 있게 돼요 😊</p>
</blockquote>
<hr>
<p><a href="https://velog.io/write?id=3cabab5e-cf73-4ac1-a48b-aa26fc1ada39">https://velog.io/write?id=3cabab5e-cf73-4ac1-a48b-aa26fc1ada39</a></p>
<h2 id="django-vs-django-drf-프레임워크-차이">Django vs Django DRF 프레임워크 차이</h2>
<hr>
<h3 id="🤔-한-줄-요약">🤔 한 줄 요약</h3>
<pre><code>Django     → 웹 페이지(HTML) 를 만드는 프레임워크
Django DRF → 데이터(JSON) 를 주고받는 프레임워크</code></pre><hr>
<h3 id="1️⃣-django-프레임워크-과정">1️⃣ Django 프레임워크 과정</h3>
<pre><code>브라우저 요청
     ↓
urls.py (URL 매칭)
     ↓
views.py (로직 처리)
     ↓
models.py (DB 조회)
     ↓
template (HTML 생성)
     ↓
HTML 페이지 응답</code></pre><h4 id="실제-코드">실제 코드</h4>
<pre><code class="language-python"># views.py
def todo_list(request):
    todos = Todo.objects.all()
    return render(           # HTML 반환!
        request,
        &quot;todo/todo.html&quot;,    # 템플릿 파일
        {&quot;todos&quot;: todos}
    )</code></pre>
<pre><code class="language-html">&lt;!-- todo.html --&gt;
{% for todo in todos %}
    &lt;p&gt;{{ todo.name }}&lt;/p&gt;
{% endfor %}</code></pre>
<pre><code>결과
────────────────────────
브라우저에 HTML 페이지가 보임
화면 + 데이터 같이 반환</code></pre><hr>
<h3 id="2️⃣-django-drf-프레임워크-과정">2️⃣ Django DRF 프레임워크 과정</h3>
<pre><code>브라우저/앱 요청
     ↓
urls.py (URL 매칭)
     ↓
views.py (로직 처리)
     ↓
models.py (DB 조회)
     ↓
serializers.py (JSON 변환)
     ↓
JSON 데이터 응답</code></pre><h4 id="실제-코드-1">실제 코드</h4>
<pre><code class="language-python"># serializers.py (DRF에만 있음!)
class TodoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Todo
        fields = &quot;__all__&quot;

# views.py
class TodoViewSet(ModelViewSet):
    queryset = Todo.objects.all()
    serializer_class = TodoSerializer  # JSON 변환!</code></pre>
<pre><code class="language-json">// 결과 - JSON 데이터 반환
{
    &quot;id&quot;: 1,
    &quot;name&quot;: &quot;공부하기&quot;,
    &quot;complete&quot;: false,
    &quot;created_at&quot;: &quot;2026-03-06&quot;
}</code></pre>
<hr>
<h3 id="3️⃣-핵심-차이점">3️⃣ 핵심 차이점</h3>
<pre><code>Django                    Django DRF
──────────────────────────────────────────
HTML 반환                 JSON 반환
render()                  Response()
템플릿 필요               템플릿 불필요
Serializer 없음           Serializer 필수
브라우저만 사용           앱/웹 모두 사용</code></pre><hr>
<h3 id="4️⃣-파일-구조-차이">4️⃣ 파일 구조 차이</h3>
<pre><code>Django                    Django DRF
──────────────────────────────────────────
models.py      ✅         models.py      ✅
views.py       ✅         views.py       ✅
urls.py        ✅         urls.py        ✅
templates/     ✅         templates/     ❌ 불필요
serializers.py ❌ 없음    serializers.py ✅ 추가됨</code></pre><hr>
<h3 id="5️⃣-viewspy-차이">5️⃣ views.py 차이</h3>
<pre><code class="language-python"># Django - 함수형 뷰
def todo_list(request):
    todos = Todo.objects.all()
    return render(request,          # HTML 반환
        &quot;todo/todo.html&quot;,
        {&quot;todos&quot;: todos})


# DRF - 클래스형 뷰
class TodoViewSet(ModelViewSet):
    queryset = Todo.objects.all()
    serializer_class = TodoSerializer
    # CRUD 자동 생성!
    # JSON 자동 반환!</code></pre>
<hr>
<h3 id="6️⃣-url-설정-차이">6️⃣ URL 설정 차이</h3>
<pre><code class="language-python"># Django urls.py
urlpatterns = [
    path(&quot;todo/&quot;, views.todo_list),      # 직접 연결
    path(&quot;todo/&lt;int:pk&gt;/&quot;, views.todo_detail),
]


# DRF urls.py
router = DefaultRouter()
router.register(&quot;todo&quot;, TodoViewSet)    # 자동 생성!

urlpatterns = [
    path(&quot;&quot;, include(router.urls)),
]

# 자동으로 이런 URL들이 생성됨
# GET    /todo/      목록 조회
# POST   /todo/      생성
# GET    /todo/1/    상세 조회
# PUT    /todo/1/    수정
# DELETE /todo/1/    삭제</code></pre>
<hr>
<h3 id="7️⃣-serializer란">7️⃣ Serializer란?</h3>
<pre><code>DRF에만 있는 핵심 개념!

DB 데이터                  JSON
────────────────────────────────
&lt;Todo: 공부하기&gt;  →  {&quot;name&quot;: &quot;공부하기&quot;}
(Python 객체)         (JSON 데이터)

역할
────────────────────────
① 데이터 변환 (Python ↔ JSON)
② 데이터 유효성 검사
③ 데이터 저장</code></pre><pre><code class="language-python">class TodoSerializer(serializers.ModelSerializer):
    class Meta:
        model = Todo           # 어떤 모델?
        fields = &quot;__all__&quot;     # 어떤 필드?</code></pre>
<hr>
<h3 id="8️⃣-언제-뭘-쓰나">8️⃣ 언제 뭘 쓰나?</h3>
<pre><code>Django 사용                DRF 사용
──────────────────────────────────────
웹사이트만 만들 때          앱도 같이 만들 때
HTML 페이지 필요할 때       API 서버 만들 때
혼자 쓰는 서비스            여러 플랫폼 서비스
블로그, 쇼핑몰              카카오, 인스타그램</code></pre><hr>
<h3 id="🗺️-전체-흐름-비교">🗺️ 전체 흐름 비교</h3>
<pre><code>Django
──────────────────────────────────────
요청 → URL → View → Model → Template → HTML


DRF
──────────────────────────────────────
요청 → URL → View → Model → Serializer → JSON


차이점
Template → Serializer 로 바뀐 것!
HTML     → JSON       으로 바뀐 것!</code></pre><hr>
<h3 id="💡-핵심-요약">💡 핵심 요약</h3>
<pre><code>Django
────────────────────────
HTML 만드는 도구
눈에 보이는 화면 제공
템플릿(HTML) 이 핵심

DRF
────────────────────────
데이터 주고받는 도구
JSON 데이터 제공
Serializer 가 핵심

결론
────────────────────────
Django  = 완성된 음식 제공 🍱
DRF     = 재료(데이터)만 제공 🥩
         (요리는 앱/프론트가 함)</code></pre><hr>
<h1 id="공부기록프로젝트-2편-코드분석-시작">공부기록프로젝트 2편 코드분석 시작~</h1>
<p><a href="https://velog.io/write?id=f38a7a87-f649-477d-922b-d65bf9720f0b">https://velog.io/write?id=f38a7a87-f649-477d-922b-d65bf9720f0b</a></p>
<ol start="3">
<li>1편 상태 먼저 점검하기</li>
</ol>
<p>모델 데이터가 중요  --&gt; URL --&gt; VIEW --&gt; TRMPLETE </p>
<p>VIEW는 많은역할을 함 그래서  1편에서 2편으로 넘어갈때  코드가 동일한지 확인체크 </p>
<hr>
<p>ModelForm을 만들고, 함수형 View 기준으로 공부기록 생성(Create), 상세(Detail), 수정(Update), 삭제(Delete), 페이지네이션까지 완성하며 브라우저 기반 CRUD 흐름을 자세히 익힙니다.</p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/6de01019-a6a8-41a9-89b7-5ce7f8d44f5b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/31115d8f-6ea9-4676-884e-d4ae58cddf0e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/f37d825d-45b6-40d2-932d-fac741ef3aa3/image.png" alt=""></p>
<hr>
<h2 id="django-crud-각-기능-역할">Django CRUD 각 기능 역할</h2>
<hr>
<ol>
<li>ModelForm 만들기<pre><code class="language-python"># models.py의 필드를 자동으로 HTML 폼으로 변환
class PostForm(ModelForm):
 class Meta:
     model = Post
     fields = [&#39;title&#39;, &#39;content&#39;]</code></pre>
<blockquote>
<p>DB 모델을 기반으로 <strong>입력 폼을 자동 생성</strong>해주는 역할</p>
</blockquote>
</li>
</ol>
<hr>
<p>질문 </p>
<p>models.py의 필드를 자동으로 HTML 폼으로 변환 class PostForm(ModelForm): class Meta: model = Post fields = [&#39;title&#39;, &#39;content&#39;] &gt; DB 모델을 기반으로 <strong>입력 폼을 자동 생성</strong>해주는 역할   모델폼은  장고내장 함수인건가?</p>
<p>답변</p>
<p>Django 내장 클래스입니다</p>
<p> 어디서 가져오나요?</p>
<pre><code class="language-python"># Django 내장 모듈에서 import
from django import forms

class PostForm(forms.ModelForm):  # Django가 제공하는 클래스 상속
    class Meta:
        model = Post
        fields = [&#39;title&#39;, &#39;content&#39;]</code></pre>
<hr>
<h1 id="멘토님교안">멘토님교안</h1>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/e89ab7aa-df3b-4383-9e8f-f89891f0de5f/image.png" alt=""></p>
<hr>
<h2 id="get-vs-post-차이">GET vs POST 차이</h2>
<h3 id="핵심-차이">핵심 차이</h3>
<table>
<thead>
<tr>
<th></th>
<th>GET</th>
<th>POST</th>
</tr>
</thead>
<tbody><tr>
<td>용도</td>
<td><strong>데이터 조회</strong></td>
<td><strong>데이터 전송/저장</strong></td>
</tr>
<tr>
<td>데이터 위치</td>
<td>URL에 노출</td>
<td>Body에 숨겨짐</td>
</tr>
<tr>
<td>보안</td>
<td>낮음</td>
<td>높음</td>
</tr>
<tr>
<td>데이터 크기</td>
<td>제한 있음</td>
<td>제한 없음</td>
</tr>
<tr>
<td>캐싱</td>
<td>가능</td>
<td>불가능</td>
</tr>
</tbody></table>
<hr>
<h3 id="눈으로-보는-차이">눈으로 보는 차이</h3>
<pre><code># GET - URL에 데이터가 보임
https://example.com/search?keyword=python&amp;page=1

# POST - URL에 데이터가 안 보임
https://example.com/login
(아이디/비밀번호는 숨겨져서 전송)</code></pre><hr>
<h3 id="django에서-사용-예시">Django에서 사용 예시</h3>
<pre><code class="language-python">def my_view(request):

    # GET 요청 - 데이터 조회할 때
    if request.method == &#39;GET&#39;:
        posts = Post.objects.all()
        return render(request, &#39;list.html&#39;, {&#39;posts&#39;: posts})

    # POST 요청 - 데이터 저장할 때
    if request.method == &#39;POST&#39;:
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()  # DB 저장</code></pre>
<hr>
<p>질문  GET POST </p>
<pre><code>GET  → 검색, 목록 조회, 상세 보기
POST → 로그인, 회원가입, 게시글 작성, 수정, 삭제</code></pre><p>HTML 폼에서</p>
<pre><code class="language-html">&lt;!-- GET 방식 --&gt;
&lt;form method=&quot;GET&quot;&gt;
    &lt;input type=&quot;text&quot; name=&quot;keyword&quot;&gt;
&lt;/form&gt;

&lt;!-- POST 방식 --&gt;
&lt;form method=&quot;POST&quot;&gt;
    {% csrf_token %}  &lt;!-- Django 보안 토큰 필수! --&gt;
    &lt;input type=&quot;text&quot; name=&quot;title&quot;&gt;
&lt;/form&gt;</code></pre>
<blockquote>
<p>💡 <strong>조회는 GET, 변경은 POST</strong> 로 기억하세요!</p>
</blockquote>
<hr>
<p>질문 장고에서의 모델 폼에대한 설명과 사용쓰임방법</p>
<h2 id="django-modelform-완벽-정리">Django ModelForm 완벽 정리</h2>
<h3 id="modelform이란">ModelForm이란?</h3>
<pre><code>DB 모델(Model) + HTML 폼(Form) 을 자동으로 연결해주는 Django 내장 클래스</code></pre><hr>
<p>기본 구조</p>
<pre><code class="language-python"># forms.py
from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post          # 어떤 모델을 사용할지
        fields = [&#39;title&#39;, &#39;content&#39;]  # 어떤 필드를 폼에 보여줄지
        # fields = &#39;__all__&#39;  # 모든 필드 사용할 때</code></pre>
<p> Model 예시</p>
<pre><code class="language-python"># models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100)    # 제목
    content = models.TextField()                # 내용
    created_at = models.DateTimeField(auto_now_add=True)  # 생성일</code></pre>
<hr>
<p>CRUD별 사용 방법</p>
<p> ✅ 생성 (Create)</p>
<pre><code class="language-python"># views.py
def post_create(request):
    if request.method == &#39;POST&#39;:
        form = PostForm(request.POST)  # 입력된 데이터 받기
        if form.is_valid():            # 유효성 검사
            form.save()                # DB 저장
            return redirect(&#39;post_list&#39;)
    else:
        form = PostForm()              # 빈 폼 생성
    return render(request, &#39;create.html&#39;, {&#39;form&#39;: form})</code></pre>
<p> ✅ 수정 (Update)</p>
<pre><code class="language-python"># views.py
def post_update(request, pk):
    post = Post.objects.get(pk=pk)
    if request.method == &#39;POST&#39;:
        form = PostForm(request.POST, instance=post)  # 기존 데이터 불러오기
        if form.is_valid():
            form.save()               # 수정된 내용 저장
            return redirect(&#39;post_list&#39;)
    else:
        form = PostForm(instance=post)  # 기존 데이터로 폼 채우기
    return render(request, &#39;update.html&#39;, {&#39;form&#39;: form})</code></pre>
<p> ✅ 삭제 (Delete)</p>
<pre><code class="language-python"># views.py
def post_delete(request, pk):
    post = Post.objects.get(pk=pk)
    if request.method == &#39;POST&#39;:
        post.delete()                 # DB에서 삭제
        return redirect(&#39;post_list&#39;)
    return render(request, &#39;delete.html&#39;, {&#39;post&#39;: post})</code></pre>
<hr>
<p>HTML 템플릿에서 사용</p>
<pre><code class="language-html">&lt;!-- create.html --&gt;
&lt;form method=&quot;POST&quot;&gt;
    {% csrf_token %}       &lt;!-- 보안 토큰 필수! --&gt;
    {{ form.as_p }}        &lt;!-- 폼 자동 렌더링 --&gt;
    &lt;button type=&quot;submit&quot;&gt;저장&lt;/button&gt;
&lt;/form&gt;</code></pre>
<p>폼 렌더링 방식 3가지</p>
<pre><code class="language-html">{{ form.as_p }}     &lt;!-- &lt;p&gt; 태그로 감싸서 출력 --&gt;
{{ form.as_table }} &lt;!-- &lt;table&gt; 태그로 출력 --&gt;
{{ form.as_ul }}    &lt;!-- &lt;ul&gt; 태그로 출력 --&gt;</code></pre>
<p>유효성 검사</p>
<pre><code class="language-python">form = PostForm(request.POST)

if form.is_valid():          # 유효성 통과 ✅
    form.save()
else:
    print(form.errors)       # 어떤 오류인지 출력 ❌</code></pre>
<p> fields 설정 방법</p>
<pre><code class="language-python">class Meta:
    model = Post
    fields = &#39;__all__&#39;                    # 모든 필드
    fields = [&#39;title&#39;, &#39;content&#39;]         # 특정 필드만 포함
    exclude = [&#39;created_at&#39;]              # 특정 필드만 제외</code></pre>
<p> 일반 Form vs ModelForm 비교</p>
<pre><code class="language-python"># ❌ 일반 Form - 직접 다 작성
class PostForm(forms.Form):
    title = forms.CharField()
    content = forms.CharField()
    # DB 저장도 직접 작성해야 함

# ✅ ModelForm - 자동 처리
class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = &#39;__all__&#39;
    # DB 저장은 form.save() 한 줄!</code></pre>
<p> 핵심 메서드 정리</p>
<table>
<thead>
<tr>
<th>메서드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>form.is_valid()</code></td>
<td>입력값 유효성 검사</td>
</tr>
<tr>
<td><code>form.save()</code></td>
<td>DB에 저장</td>
</tr>
<tr>
<td><code>form.errors</code></td>
<td>오류 내용 확인</td>
</tr>
<tr>
<td><code>form.as_p()</code></td>
<td>p태그로 렌더링</td>
</tr>
<tr>
<td><code>instance=post</code></td>
<td>기존 데이터 불러오기</td>
</tr>
</tbody></table>
<blockquote>
<p>💡 <strong>ModelForm = 모델 기반 자동 폼 생성 + 유효성 검사 + DB 저장</strong> 을 한번에 처리해주는 Django의 핵심 기능입니다!</p>
</blockquote>
<hr>
<p>질문 Django Form / ModelForm은 왜 필요하며  둘 차이점?</p>
<p> Django Form vs ModelForm</p>
<p> 왜 필요한가?</p>
<pre><code>HTML 폼만 사용하면 아래를 전부 직접 작성해야 함 😱

1. HTML input 태그 하나하나 작성
2. 유효성 검사 직접 작성
3. DB 저장 코드 직접 작성
4. 보안 처리 직접 작성

→ Form / ModelForm 사용하면 자동으로 해결! 😊</code></pre><p> Django Form</p>
<pre><code class="language-python"># forms.py
from django import forms

class PostForm(forms.Form):
    title = forms.CharField(max_length=100)   # 직접 필드 정의
    content = forms.CharField()               # 직접 필드 정의</code></pre>
<pre><code class="language-python"># views.py
def post_create(request):
    if request.method == &#39;POST&#39;:
        form = PostForm(request.POST)
        if form.is_valid():
            # ❌ DB 저장 코드를 직접 작성해야 함
            Post.objects.create(
                title=form.cleaned_data[&#39;title&#39;],
                content=form.cleaned_data[&#39;content&#39;]
            )
    else:
        form = PostForm()
    return render(request, &#39;create.html&#39;, {&#39;form&#39;: form})</code></pre>
<p> Django ModelForm</p>
<pre><code class="language-python"># forms.py
from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post          # 모델 연결
        fields = &#39;__all__&#39;    # 필드 자동 생성</code></pre>
<pre><code class="language-python"># views.py
def post_create(request):
    if request.method == &#39;POST&#39;:
        form = PostForm(request.POST)
        if form.is_valid():
            form.save()       # ✅ 한 줄로 DB 저장
    else:
        form = PostForm()
    return render(request, &#39;create.html&#39;, {&#39;form&#39;: form})</code></pre>
<p>핵심 차이점</p>
<table>
<thead>
<tr>
<th></th>
<th>Form</th>
<th>ModelForm</th>
</tr>
</thead>
<tbody><tr>
<td>필드 정의</td>
<td><strong>직접</strong> 작성</td>
<td>모델에서 <strong>자동</strong> 생성</td>
</tr>
<tr>
<td>DB 저장</td>
<td><strong>직접</strong> 작성</td>
<td><code>form.save()</code> 한 줄</td>
</tr>
<tr>
<td>모델 연결</td>
<td>❌ 없음</td>
<td>✅ 자동 연결</td>
</tr>
<tr>
<td>코드량</td>
<td>많음</td>
<td>적음</td>
</tr>
<tr>
<td>유효성 검사</td>
<td>✅ 가능</td>
<td>✅ 가능</td>
</tr>
<tr>
<td>사용 상황</td>
<td>DB 불필요한 폼</td>
<td>DB 연동 필요한 폼</td>
</tr>
</tbody></table>
<p> 언제 무엇을 쓰나요?</p>
<pre><code>✅ Form 사용
- 로그인 (DB 저장 없이 검증만)
- 검색 폼
- 이메일 문의 폼
- DB와 관계없는 데이터 처리

✅ ModelForm 사용
- 게시글 작성/수정
- 회원가입
- 댓글 작성
- DB에 저장이 필요한 모든 것</code></pre><p> 한눈에 비교</p>
<pre><code class="language-python"># Form - 검색 폼 예시 (DB 저장 X)
class SearchForm(forms.Form):
    keyword = forms.CharField()

# ModelForm - 게시글 폼 (DB 저장 O)
class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = &#39;__all__&#39;</code></pre>
<blockquote>
<p>💡 <strong>DB 저장이 필요하면 ModelForm, 아니면 Form!</strong>
ModelForm은 Form의 기능을 모두 포함하면서 DB 연동까지 자동으로 해줍니다.</p>
</blockquote>
<hr>
<hr>
<h1 id="질문-답변">질문 답변</h1>
<h2 id="form--modelform을-쓰는-이유--나의질문-폼이랑-모델폼차이가-이해가-안되신다는건가용">Form / ModelForm을 쓰는 이유  나의질문 폼이랑 모델폼차이가 이해가 안되신다는건가용??</h2>
<p>Study 모델 정의
→ ModelForm 작성
→ 폼에서 입력값 검증
→ form.save()로 모델 저장</p>
<h2 id="답변-2">답변</h2>
<ul>
<li><p>스터디 모델을 1편에서 만들었잖아요?
그 모델이랑 연결되는 form을 만들라는거에용
모델과 연관성있는 것 무언가 입력을 받는 구조의 폼이라고 생각 </p>
</li>
<li><p>Form은
그냥 입력창을 만드는 도구
어떤 값을 받을지 직접 다 적어줘야 함
저장도 직접 해야 함</p>
</li>
</ul>
<p>즉, “입력만 받는 일반 양식”이라고 이해하시면 됩니다.</p>
<ul>
<li>ModelForm은
모델을 기준으로 폼을 쉽게 만드는 도구
모델 필드를 바탕으로 입력창을 만들 수 있음
검증도 도와주고, form.save()로 DB 저장도 쉬움</li>
</ul>
<p>즉, “모델이랑 연결된 폼”이라고 이해하시면 됩니다.</p>
<ul>
<li><p>우리가 템플릿에서 보는 <form> 태그는
사용자가 값을 입력해서 보내는 HTML 영역이에요!</p>
</li>
<li><p>사용자가 입력한 값이 서버로 전달되면,
서버에서 ModelForm이 그 값을 받아 검증하고,
문제가 없으면 저장한다고 생각하시면 됩니당</p>
<hr>
</li>
</ul>
<h2 id="나의질문-1">나의질문</h2>
<p>study 앱에  폼을 만들고 그 폼이라는것은 그냥 앱 생성할때마다 만드는 폼이라고 생각하면되나요.. 그리고 그안에   CRUS페이지까지  스터디앱에 만드는거죠? </p>
<h2 id="답변-3">답변</h2>
<p>폼은 앱 만들 때 무조건 만드는 게 아니라, 사용자의 입력을 받아야 할 때 만드는 거예요! 항상 만드는건 아니에용 그리고 Study 앱을 만들었으니까, Study 관련 CRUD 페이지도 그 앱 안에서 같이 만듭니다  </p>
<hr>
<h1 id="form-vs-modelform-적용-범위-1">Form vs ModelForm 적용 범위</h1>
<p><strong>아니요, 둘 다 모델 파일과 독립적으로 사용할 수 있습니다.</strong></p>
<hr>
<h3 id="formsform--모델과-무관-1"><code>forms.Form</code> — 모델과 <strong>무관</strong></h3>
<pre><code class="language-python">class ContactForm(forms.Form):
    name = forms.CharField()
    email = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)</code></pre>
<ul>
<li>모델 없이 순수하게 입력값 처리/검증만 할 때 사용</li>
<li>예: 문의 폼, 검색 폼, 로그인 폼, 계산기 폼 등</li>
</ul>
<hr>
<h3 id="formsmodelform--모델과-연결됨-1"><code>forms.ModelForm</code> — 모델과 <strong>연결됨</strong></h3>
<pre><code class="language-python">class StudyForm(forms.ModelForm):
    class Meta:
        model = Study  # ← 특정 모델에 종속
        fields = [...]</code></pre>
<ul>
<li>반드시 <code>Meta.model</code>에 연결할 모델이 필요</li>
<li><code>form.save()</code>로 DB에 바로 저장 가능</li>
</ul>
<hr>
<h3 id="정리-1">정리</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>모델 필요 여부</th>
<th>DB 저장</th>
</tr>
</thead>
<tbody><tr>
<td><code>forms.Form</code></td>
<td>❌ 불필요</td>
<td>직접 처리해야 함</td>
</tr>
<tr>
<td><code>forms.ModelForm</code></td>
<td>✅ 필수</td>
<td><code>form.save()</code>로 자동</td>
</tr>
</tbody></table>
<p>즉, <strong><code>ModelForm</code>만 모델 파일에 해당</strong>되고, <code>Form</code>은 모델 없이 어디서든 독립적으로 사용할 수 있습니다.</p>
<hr>
<h2 id="1-formsform이-필요한-때-1">1. <code>forms.Form</code>이 필요한 때</h2>
<p>모델에 저장할 필요 없이 <strong>입력값만 처리</strong>할 때 사용합니다.</p>
<pre><code class="language-python"># 예시 1 - 검색 폼
class SearchForm(forms.Form):
    keyword = forms.CharField()
    # 검색어를 받아서 필터링만 할 뿐, DB에 저장 안 함

# 예시 2 - 로그인 폼
class LoginForm(forms.Form):
    username = forms.CharField()
    password = forms.CharField(widget=forms.PasswordInput)
    # 인증만 하고 저장 X

# 예시 3 - 문의/이메일 폼
class ContactForm(forms.Form):
    email = forms.EmailField()
    message = forms.CharField()
    # 이메일로 전송만 하고 저장 X</code></pre>
<hr>
<h2 id="2-메서드라는-표현에-대해-1">2. &quot;메서드&quot;라는 표현에 대해</h2>
<p><strong>정확히는 구분해서 불러야 합니다.</strong></p>
<table>
<thead>
<tr>
<th>용어</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><strong>클래스(Class)</strong></td>
<td>설계도 전체</td>
<td><code>StudyForm</code>, <code>LoginForm</code></td>
</tr>
<tr>
<td><strong>메서드(Method)</strong></td>
<td>클래스 안의 함수</td>
<td><code>clean_minutes()</code>, <code>save()</code></td>
</tr>
<tr>
<td><strong>필드(Field)</strong></td>
<td>클래스 안의 변수/속성</td>
<td><code>title</code>, <code>email</code></td>
</tr>
</tbody></table>
<pre><code class="language-python">class StudyForm(forms.ModelForm):  # ← 클래스

    title = forms.CharField()      # ← 필드

    def clean_minutes(self):       # ← 메서드
        ...</code></pre>
<p>그래서</p>
<ul>
<li><code>StudyForm</code> 자체 → <strong>클래스</strong></li>
<li><code>clean_minutes()</code> → <strong>메서드</strong></li>
<li><code>forms.Form</code>, <code>forms.ModelForm</code> → <strong>클래스를 상속</strong>받는 것</li>
</ul>
<p>&quot;Form이랑 ModelForm 메서드야?&quot; 라고 하면 엄밀히는 <strong>클래스</strong>라고 표현하는 게 맞습니다.</p>
<hr>
<h3 id="5-modelform-만들기">5. ModelForm 만들기</h3>
<p>이제 실제로 Study 모델과 연결되는 StudyForm을 만듭니다.</p>
<p> ModelForm이 자동으로 해주는 것</p>
<table>
<thead>
<tr>
<th>기능</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>필드 자동 생성</td>
<td>모델의 필드를 자동으로 HTML <code>&lt;input&gt;</code>으로 변환</td>
</tr>
<tr>
<td>유효성 검사</td>
<td>입력값이 올바른지 자동 검증</td>
</tr>
<tr>
<td>DB 저장</td>
<td><code>.save()</code> 한 줄로 DB에 바로 저장</td>
</tr>
</tbody></table>
<p>직접 만들 때 vs ModelForm 비교</p>
<pre><code class="language-python">
# ❌ 직접 만들 때 (길고 복잡)
&lt;input type=&quot;text&quot; name=&quot;title&quot;&gt;
&lt;input type=&quot;text&quot; name=&quot;content&quot;&gt;
# 유효성 검사도 직접 작성...
# DB 저장도 직접 작성...

# ✅ ModelForm 사용 (간단!)
form = PostForm()  # 끝!
form.save()        # DB 저장도 한 줄!</code></pre>
<p> 결론</p>
<pre><code>Django 내장 클래스 ✅
별도 설치 불필요 ✅
from django import forms 로 바로 사용 가능 ✅</code></pre><blockquote>
<p>💡 Django가 반복적인 폼 작업을 <strong>자동화</strong>해주기 위해 만든 강력한 내장 기능입니다!</p>
</blockquote>
<h3 id="2-생성-create">2. 생성 (Create)</h3>
<pre><code>사용자가 폼에 데이터 입력 → DB에 새 데이터 저장
예) 게시글 작성, 회원가입</code></pre><blockquote>
<p><strong>새로운 데이터를 추가</strong>하는 기능</p>
</blockquote>
<h3 id="3-상세-detail">3. 상세 (Detail)</h3>
<pre><code>목록에서 항목 클릭 → 해당 데이터 상세 내용 표시
예) 게시글 본문 보기</code></pre><blockquote>
<p><strong>특정 데이터 하나를 자세히 조회</strong>하는 기능</p>
</blockquote>
<h3 id="4-수정-update">4. 수정 (Update)</h3>
<pre><code>기존 데이터를 불러와 폼에 표시 → 수정 후 저장
예) 게시글 편집</code></pre><blockquote>
<p><strong>기존 데이터를 변경</strong>하는 기능</p>
</blockquote>
<h3 id="5-삭제-delete">5. 삭제 (Delete)</h3>
<pre><code>특정 데이터 선택 → DB에서 완전 삭제
예) 게시글 삭제</code></pre><blockquote>
<p><strong>데이터를 DB에서 제거</strong>하는 기능</p>
</blockquote>
<h3 id="6-페이지네이션-pagination">6. 페이지네이션 (Pagination)</h3>
<pre><code>데이터가 많을 때 → 한 페이지에 n개씩 나눠서 표시
예) 1페이지, 2페이지, 3페이지...</code></pre><blockquote>
<p><strong>많은 데이터를 나눠서 보여주는</strong> 기능</p>
</blockquote>
<h3 id="전체-흐름-요약">전체 흐름 요약</h3>
<pre><code>ModelForm        → 입력 폼 자동 생성
Create (생성)    → 데이터 추가 (INSERT)
Detail (상세)    → 데이터 1개 조회 (SELECT)
Update (수정)    → 데이터 변경 (UPDATE)
Delete (삭제)    → 데이터 제거 (DELETE)
Pagination       → 데이터 분할 표시</code></pre><blockquote>
<p>💡 이 6가지가 합쳐지면 <strong>브라우저 기반 CRUD 완성</strong>입니다!</p>
</blockquote>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/15a7d26e-4034-472d-b489-59588a1e53bf/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/34bc47ad-556f-4368-aa7f-5042f4324856/image.png" alt=""></p>
<h1 id="왜-이-순서인가-1">왜 이 순서인가?</h1>
<p>이 순서는 기능을 그냥 나열한 것이 아닙니다.</p>
<p>예를 들어:</p>
<p>폼이 있어야 생성/수정 기능을 만들 수 있습니다.
상세 페이지가 있어야 수정/삭제 이후 이동 흐름도 자연스러워집니다.
CRUD가 어느 정도 끝나야 페이지네이션을 실제로 체감할 수 있습니다.
즉 이번 교안도 여전히 실제 실습 순서 기준으로 설계되어 있습니다.</p>
<hr>
<p>2번 하기전 준비</p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/51e63e67-141f-4658-984d-40c72f125e44/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/e68d2d7f-3cf1-46ce-af29-af5379b147dd/image.png" alt=""></p>
<hr>
<ol start="6">
<li>생성(Create) 기능을 만들기 전에 URL부터 추가하기</li>
</ol>
<pre><code>
path() 구조 분석
pythonpath(&#39;&#39;, views.study_list, name=&#39;list&#39;)
path(경로, 뷰함수, name=이름) — 총 3개의 인자로 구성됩니다.
</code></pre><h3 id="1-formsave-한-줄로-저장되는-이유">1. <code>form.save()</code> 한 줄로 저장되는 이유</h3>
<p>쉽게 비유하면:</p>
<pre><code>일반 Form    = 그냥 빈 종이
ModelForm   = Study 모델과 연결된 자동완성 종이</code></pre><pre><code class="language-python"># ModelForm은 이미 내부에 이런 동작이 내장되어 있음
class StudyForm(forms.ModelForm):
    class Meta:
        model = Study          # ← &quot;나는 Study랑 연결됐어&quot;
        fields = [&#39;title&#39;, ...] # ← &quot;이 필드들을 저장해&quot;

# 그래서 form.save() 한 줄이
# 내부적으로 이걸 자동으로 해줌
study = Study(
    title = form.cleaned_data[&#39;title&#39;],
    category = form.cleaned_data[&#39;category&#39;],
    ...
)
study.save()  # DB 저장</code></pre>
<blockquote>
<p><code>form.save()</code> = &quot;연결된 모델에 알아서 넣고 저장해줘&quot; 라는 명령</p>
</blockquote>
<ol start="2">
<li>코드 구조 정체</li>
</ol>
<pre><code class="language-python">from django.shortcuts import redirect, render  # ← 임포트
from .forms import StudyForm                   # ← 임포트
from .models import Study                      # ← 임포트</code></pre>
<p><strong>import</strong> = 다른 파일에서 필요한 것만 가져오는 것</p>
<ul>
<li><code>from 어디서</code> <code>import 무엇을</code></li>
</ul>
<pre><code class="language-python">def study_list(request):   # ← 함수
    ...
    return render(...)

def study_create(request): # ← 함수
    ...
    return render(...)</code></pre>
<p><strong>def = 함수입니다</strong> (메서드 아님)</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>위치</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><strong>함수</strong></td>
<td>클래스 밖에 독립적으로 존재</td>
<td><code>def study_list(request)</code></td>
</tr>
<tr>
<td><strong>메서드</strong></td>
<td>클래스 안에 존재</td>
<td><code>def clean_minutes(self)</code></td>
</tr>
</tbody></table>
<pre><code class="language-python">def study_create(request):
    form = StudyForm(request.POST or None)

    if request.method == &#39;POST&#39; and form.is_valid():
        form.save()
        return redirect(&#39;study:list&#39;)   # ← if 안의 return

    return render(request, &#39;study/study_form.html&#39;, {...})  # ← 함수의 return</code></pre>
<p><strong>return이 2개인 이유</strong></p>
<pre><code>사용자가 처음 페이지 접속 (GET 요청)
    → if 조건 False → 아래 render() 실행 → 폼 화면 보여줌

사용자가 폼 작성 후 제출 (POST 요청)
    → if 조건 True → form.save() → redirect로 목록으로 이동</code></pre><h3 id="전체-구조-한눈에">전체 구조 한눈에</h3>
<pre><code class="language-python"># 1. 임포트 (재료 가져오기)
from django.shortcuts import redirect, render

# 2. 함수 정의 (클래스 밖 → 함수)
def study_create(request):

    # 3. 변수 선언
    form = StudyForm(request.POST or None)

    # 4. 조건 분기
    if request.method == &#39;POST&#39; and form.is_valid():
        form.save()
        return redirect(&#39;study:list&#39;)  # POST면 여기서 끝

    return render(...)  # GET이면 여기서 끝</code></pre>
<blockquote>
<p>핵심: <code>def</code>가 <strong>클래스 밖</strong>에 있으면 → <strong>함수</strong>, <strong>클래스 안</strong>에 있으면 → <strong>메서드</strong></p>
</blockquote>
<ol start="7">
<li>생성(Create) View 작성
어려움  </li>
</ol>
<p>이제 study_create View를 추가합니다.</p>
<ol start="8">
<li>생성 / 수정 공용 폼 템플릿 만들기</li>
</ol>
<hr>
<h2 id="html-템플릿-큰-그림-분석">HTML 템플릿 큰 그림 분석</h2>
<h3 id="1-상속-구조">1. 상속 구조</h3>
<pre><code class="language-html">{% extends &#39;base.html&#39; %}</code></pre>
<ul>
<li>이 파일은 <code>base.html</code>을 <strong>부모</strong>로 삼음</li>
<li>즉, base.html의 공통 레이아웃(헤더, 푸터 등)을 그대로 가져오고</li>
<li><strong>다른 부분만 여기서 채워 넣는 구조</strong></li>
</ul>
<h3 id="2-block-2개">2. block 2개</h3>
<pre><code class="language-html">{% block title %}
    {{ page_title }} | 공부시간 기록기
{% endblock %}

{% block content %}
    ... 실제 내용 ...
{% endblock %}</code></pre>
<ul>
<li><code>block</code> = base.html에 뚫어놓은 <strong>구멍</strong></li>
<li>이 파일이 그 구멍을 <strong>채워넣는 역할</strong></li>
<li><code>title</code> → 브라우저 탭 제목</li>
<li><code>content</code> → 실제 화면에 보이는 내용 전체</li>
</ul>
<h3 id="3-content-안-구조">3. content 안 구조</h3>
<pre><code>{% block content %}
    │
    ├── section.hero-card       ← 상단 소개 영역
    │       제목, 설명글
    │
    └── section.content-card    ← 실제 폼 영역
            form</code></pre><p><strong>hero-card (소개 영역)</strong></p>
<pre><code class="language-html">&lt;section class=&quot;hero-card&quot;&gt;
    &lt;span&gt;Study Form&lt;/span&gt;          &lt;!-- 작은 라벨 --&gt;
    &lt;h1&gt;{{ page_title }}&lt;/h1&gt;        &lt;!-- 큰 제목 (views.py에서 전달) --&gt;
    &lt;p&gt;오늘의 공부를 구체적으로...&lt;/p&gt; &lt;!-- 설명글 --&gt;
&lt;/section&gt;</code></pre>
<p><strong>content-card (폼 영역)</strong></p>
<pre><code class="language-html">&lt;section class=&quot;content-card&quot;&gt;
    &lt;form method=&quot;post&quot;&gt;
        {% csrf_token %}   &lt;!-- 보안 토큰 --&gt;

        공부 제목
        카테고리
        공부 날짜
        시간 / 분       ← 이 둘은 나란히 배치 (inline-2)
        메모

        저장하기 버튼 / 목록으로 버튼
    &lt;/form&gt;
&lt;/section&gt;</code></pre>
<hr>
<h3 id="4-폼-필드-패턴-반복구조">4. 폼 필드 패턴 (반복구조)</h3>
<p>모든 필드가 <strong>똑같은 패턴</strong>으로 반복됩니다</p>
<pre><code class="language-html">&lt;div class=&quot;form-row&quot;&gt;

    &lt;!-- 라벨 --&gt;
    &lt;label for=&quot;{{ form.title.id_for_label }}&quot;&gt;
        {{ form.title.label }}
    &lt;/label&gt;

    &lt;!-- 입력창 --&gt;
    {{ form.title }}

    &lt;!-- 에러 메시지 (있을 때만 표시) --&gt;
    {% if form.title.errors %}
        {{ form.title.errors }}
    {% endif %}

&lt;/div&gt;</code></pre>
<table>
<thead>
<tr>
<th>부분</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td><code>label</code></td>
<td>입력창 설명 텍스트</td>
</tr>
<tr>
<td><code>{{ form.title }}</code></td>
<td>실제 input 태그 렌더링</td>
</tr>
<tr>
<td><code>form.title.errors</code></td>
<td>검증 실패시 에러 출력</td>
</tr>
</tbody></table>
<hr>
<h3 id="5-특이한-부분-2가지">5. 특이한 부분 2가지</h3>
<p><strong>① 시간/분 나란히 배치</strong></p>
<pre><code class="language-html">&lt;div class=&quot;form-row inline-2&quot;&gt;
    &lt;div&gt; 시간 입력 &lt;/div&gt;
    &lt;div&gt; 분 입력 &lt;/div&gt;
&lt;/div&gt;</code></pre>
<ul>
<li><code>inline-2</code> 클래스로 두 개를 <strong>가로로 나란히</strong> 배치</li>
</ul>
<p><strong>② 보안 토큰</strong></p>
<pre><code class="language-html">&lt;form method=&quot;post&quot;&gt;
    {% csrf_token %}</code></pre>
<ul>
<li>POST 요청시 <strong>반드시</strong> 필요</li>
<li>없으면 Django가 요청을 <strong>거부</strong>함</li>
<li>외부에서 악의적인 요청을 막는 보안 장치</li>
</ul>
<h3 id="전체-흐름-한줄-요약">전체 흐름 한줄 요약</h3>
<pre><code>base.html 레이아웃 상속
    → 소개 영역 (hero-card)
    → 폼 영역 (content-card)
        → 필드마다 라벨 + 입력창 + 에러메시지 패턴 반복
        → 저장 or 목록으로 버튼</code></pre><ol start="9">
<li><p>CSS에 폼 관련 스타일 추가하기</p>
</li>
<li><p>브라우저에서 생성 기능 먼저 확인하기</p>
</li>
</ol>
<ol start="11">
<li>상세(Detail) 기능을 만들기 전에 URL 추가하기</li>
</ol>
<ol start="12">
<li>상세(Detail) View 작성 </li>
</ol>
<ol start="13">
<li>상세 페이지 템플릿 만들기</li>
</ol>
<ol start="14">
<li>목록 페이지에 상세 보기 링크 연결하기</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[CharField 기초적인 개념]]></title>
            <link>https://velog.io/@hy_1023/CharField-%EA%B8%B0%EC%B4%88%EC%A0%81%EC%9D%B8-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@hy_1023/CharField-%EA%B8%B0%EC%B4%88%EC%A0%81%EC%9D%B8-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Tue, 07 Apr 2026 08:04:15 GMT</pubDate>
            <description><![CDATA[<p><code>CharField</code>는 Django 모델에서 가장 자주 쓰는 필드 중 하나로, 짧은 텍스트를 저장하는 칸입니다. 이름, 제목, 주소처럼 한 줄짜리 글자를 담을 때 씁니다.</p>
<p>아래 흐름도로 전체 개념을 한눈에 확인해 보세요.---</p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/089f8017-9a3a-4a6d-aff2-b413100392f1/image.png" alt=""></p>
<h2 id="핵심-개념-정리">핵심 개념 정리</h2>
<h3 id="charfield--짧은-글자를-저장하는-칸">CharField = &quot;짧은 글자를 저장하는 칸&quot;</h3>
<p>엑셀의 셀 하나라고 생각하면 쉬워요. 이름, 제목, 브랜드명처럼 한 줄짜리 텍스트를 담는 용도입니다.</p>
<pre><code class="language-python">name = models.CharField(max_length=100)</code></pre>
<p>이 한 줄이 DB에 <code>VARCHAR(100)</code> 컬럼 하나를 만들어 줍니다.</p>
<hr>
<h3 id="옵션-설명">옵션 설명</h3>
<table>
<thead>
<tr>
<th>옵션</th>
<th>역할</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>max_length</code></td>
<td>최대 글자 수 (필수!)</td>
<td><code>max_length=100</code></td>
</tr>
<tr>
<td><code>blank=True</code></td>
<td>폼에서 비워도 됨</td>
<td>선택 입력 항목에 사용</td>
</tr>
<tr>
<td><code>null=True</code></td>
<td>DB에 NULL 저장 허용</td>
<td>blank와 함께 쓸 때가 많음</td>
</tr>
<tr>
<td><code>default=&#39;&#39;</code></td>
<td>기본값 설정</td>
<td>아무것도 안 입력하면 이 값</td>
</tr>
</tbody></table>
<blockquote>
<p><code>blank</code>와 <code>null</code>의 차이가 헷갈릴 수 있는데, <code>blank</code>는 <strong>&quot;폼 입력 검증&quot;</strong>, <code>null</code>은 <strong>&quot;DB 저장&quot;</strong> 의 문제입니다.</p>
</blockquote>
<hr>
<h3 id="charfield를-써야-할-때-vs-말아야-할-때">CharField를 써야 할 때 vs 말아야 할 때</h3>
<ul>
<li>써야 할 때: 이름, 제목, 주소, 전화번호처럼 짧은 한 줄 텍스트</li>
<li><code>TextField</code> 써야 할 때: 게시글 본문, 리뷰 내용처럼 길고 제한 없는 텍스트</li>
<li><code>IntegerField</code> 써야 할 때: 나이, 가격처럼 숫자</li>
</ul>
<p>궁금한 옵션이 있으면 다이어그램의 각 박스를 클릭해 더 물어볼 수 있어요! 😊</p>
<hr>
<p>CharField blank 옵션이 뭔가요?</p>
<h2 id="blanktrue-옵션이란"><code>blank=True</code> 옵션이란?</h2>
<p><code>blank</code>는 <strong>폼(Form) 입력 시 이 칸을 비워도 되는지</strong> 를 결정하는 옵션입니다.</p>
<hr>
<h3 id="가장-쉬운-비유">가장 쉬운 비유</h3>
<blockquote>
<p>회원가입 페이지를 떠올려보세요.</p>
<ul>
<li>이름 입력칸 → <strong>필수</strong> (비우면 &quot;이름을 입력해주세요&quot; 오류)</li>
<li>닉네임 입력칸 → <strong>선택</strong> (비워도 통과)</li>
</ul>
<p>이 &quot;선택 칸&quot;을 만들 때 <code>blank=True</code>를 씁니다.</p>
</blockquote>
<hr>
<h3 id="코드-비교">코드 비교</h3>
<pre><code class="language-python">class User(models.Model):
    username = models.CharField(max_length=50)
    # blank 없음 = 기본값이 blank=False
    # → 폼에서 반드시 입력해야 함

    nickname = models.CharField(max_length=50, blank=True)
    # → 폼에서 비워도 통과됨</code></pre>
<hr>
<h3 id="blank-vs-null-차이-자주-헷갈리는-부분"><code>blank</code> vs <code>null</code> 차이 (자주 헷갈리는 부분!)</h3>
<table>
<thead>
<tr>
<th>옵션</th>
<th>언제 작동하나?</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td><code>blank=True</code></td>
<td>폼 입력할 때</td>
<td>&quot;이 칸 안 채워도 됩니다&quot;</td>
</tr>
<tr>
<td><code>null=True</code></td>
<td>DB에 저장할 때</td>
<td>&quot;DB에 NULL 값 저장 허용&quot;</td>
</tr>
</tbody></table>
<p><code>CharField</code>는 보통 <code>null=True</code> 없이 <code>blank=True</code>만 써도 충분합니다. 비어있을 때 DB에 <code>NULL</code> 대신 빈 문자열 <code>&#39;&#39;</code>을 저장하기 때문입니다.</p>
<pre><code class="language-python"># CharField 권장 패턴
nickname = models.CharField(max_length=50, blank=True, default=&#39;&#39;)
#                                           ↑ 폼 비워도 됨  ↑ 빈 문자열로 저장</code></pre>
<hr>
<h3 id="한-줄-요약">한 줄 요약</h3>
<blockquote>
<p><code>blank=True</code> = <strong>&quot;이 항목은 선택 입력입니다&quot;</strong> 라고 Django에게 알려주는 것</p>
</blockquote>
<p>추가로 궁금한 옵션 있으면 알려주세요! 😊</p>
<hr>
<p>CharField null 옵션이 뭔가요?</p>
<h2 id="nulltrue-옵션이란"><code>null=True</code> 옵션이란?</h2>
<p><code>null</code>은 <strong>DB(데이터베이스)에 저장할 때 &quot;값 없음&quot;을 NULL로 저장할지</strong> 를 결정하는 옵션입니다.</p>
<hr>
<h3 id="가장-쉬운-비유-1">가장 쉬운 비유</h3>
<blockquote>
<p>엑셀 셀을 떠올려보세요.</p>
<ul>
<li>셀에 <strong>빈 문자열</strong> <code>&#39;&#39;</code> 저장 → 셀이 존재하는데 내용이 없는 것</li>
<li>셀에 <strong>NULL</strong> 저장 → 셀 자체에 &quot;아무 값도 없음&quot; 표시</li>
</ul>
<p>이 두 가지는 DB 입장에서 <strong>다른 값</strong>입니다.</p>
</blockquote>
<hr>
<h3 id="코드-비교-1">코드 비교</h3>
<pre><code class="language-python">class User(models.Model):

    nickname = models.CharField(max_length=50, blank=True)
    # null=True 없음 → 비어있으면 DB에 &#39;&#39; (빈 문자열) 저장

    bio = models.CharField(max_length=200, blank=True, null=True)
    # null=True 있음 → 비어있으면 DB에 NULL 저장</code></pre>
<hr>
<h3 id="db에-실제로-어떻게-저장되나">DB에 실제로 어떻게 저장되나?</h3>
<table>
<thead>
<tr>
<th>상황</th>
<th><code>null=True</code> 없을 때</th>
<th><code>null=True</code> 있을 때</th>
</tr>
</thead>
<tbody><tr>
<td>닉네임 입력 안 함</td>
<td><code>&#39;&#39;</code> (빈 문자열)</td>
<td><code>NULL</code></td>
</tr>
<tr>
<td>닉네임 입력함</td>
<td><code>&#39;heeyoung&#39;</code></td>
<td><code>&#39;heeyoung&#39;</code></td>
</tr>
</tbody></table>
<hr>
<h3 id="blank-vs-null-한눈에-비교"><code>blank</code> vs <code>null</code> 한눈에 비교</h3>
<pre><code>blank=True   →   폼(화면) 단계에서 작동   →   &quot;입력 안 해도 됨&quot;
null=True    →   DB 저장 단계에서 작동    →   &quot;NULL로 저장 허용&quot;</code></pre><br>

<pre><code>사용자가 폼에 아무것도 안 입력
        ↓
   blank=True?  ─── No ──→  &quot;필수 항목입니다&quot; 오류 발생
        │
       Yes
        ↓
   DB에 저장할 때
   null=True?  ─── No ──→  &#39;&#39; (빈 문자열) 로 저장
        │
       Yes
        ↓
    NULL 로 저장</code></pre><hr>
<h3 id="charfield에서-권장하는-패턴">CharField에서 권장하는 패턴</h3>
<p><code>CharField</code>는 <code>null=True</code>를 <strong>되도록 쓰지 않는 것</strong>이 Django 권장 방식입니다. &quot;값 없음&quot;을 표현하는 방법이 <code>NULL</code>과 <code>&#39;&#39;</code> 두 가지가 생겨서 나중에 조회할 때 혼란스럽기 때문입니다.</p>
<pre><code class="language-python"># 권장
nickname = models.CharField(max_length=50, blank=True, default=&#39;&#39;)

# 비권장 (CharField에서)
nickname = models.CharField(max_length=50, blank=True, null=True)</code></pre>
<blockquote>
<p><code>null=True</code>는 <code>CharField</code>보다 <code>IntegerField</code>, <code>DateField</code> 같은 숫자/날짜 필드에서 더 자연스럽게 씁니다. 숫자 필드는 &quot;값 없음&quot;을 <code>0</code>으로 표현하면 의미가 달라지기 때문입니다.</p>
</blockquote>
<hr>
<h3 id="한-줄-요약-1">한 줄 요약</h3>
<blockquote>
<p><code>null=True</code> = <strong>&quot;이 칸이 비어있을 때 DB에 NULL로 저장해도 됩니다&quot;</strong> 라고 Django에게 알려주는 것</p>
</blockquote>
<p>궁금한 게 있으면 더 물어보세요! 😊</p>
<hr>
<p>CharField max_length 옵션이 뭔가요?</p>
<h2 id="max_length-옵션이란"><code>max_length</code> 옵션이란?</h2>
<p><code>max_length</code>는 <strong>이 칸에 입력할 수 있는 최대 글자 수</strong>를 정하는 옵션입니다. <code>CharField</code>에서 <strong>반드시 써야 하는 필수 옵션</strong>입니다.</p>
<hr>
<h3 id="가장-쉬운-비유-2">가장 쉬운 비유</h3>
<blockquote>
<p>종이 서류의 입력칸을 떠올려보세요.</p>
<ul>
<li>이름 칸 → <code>[ _ _ _ _ _ _ _ _ _ _ ]</code> (10칸)</li>
<li>주소 칸 → <code>[ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ]</code> (20칸)</li>
</ul>
<p><code>max_length</code>는 이 <strong>칸의 크기</strong>를 정하는 것입니다.</p>
</blockquote>
<hr>
<h3 id="코드">코드</h3>
<pre><code class="language-python">class User(models.Model):
    username = models.CharField(max_length=50)
    # 최대 50글자까지만 저장 가능

    email = models.CharField(max_length=200)
    # 최대 200글자까지 저장 가능</code></pre>
<hr>
<h3 id="max_length가-하는-일-2가지">max_length가 하는 일 2가지</h3>
<pre><code>max_length=50 설정 시

① DB 테이블 생성할 때
   → VARCHAR(50) 컬럼으로 만들어짐
   → DB 자체에서 50자 초과 저장 차단

② 폼(화면) 입력할 때
   → 51자 이상 입력하면 &quot;이 필드의 최대 길이는 50입니다&quot; 오류 발생
   → Django가 자동으로 검증해줌</code></pre><hr>
<h3 id="적절한-max_length-값-가이드">적절한 max_length 값 가이드</h3>
<table>
<thead>
<tr>
<th>저장할 내용</th>
<th>권장 값</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>이름, 닉네임</td>
<td><code>50</code></td>
<td>대부분 50자 이내</td>
</tr>
<tr>
<td>이메일 주소</td>
<td><code>200</code></td>
<td>이메일 최대 길이 규격</td>
</tr>
<tr>
<td>제목, 상품명</td>
<td><code>100~200</code></td>
<td>여유 있게 설정</td>
</tr>
<tr>
<td>주소</td>
<td><code>255</code></td>
<td>긴 주소 대비</td>
</tr>
<tr>
<td>비밀번호(해시)</td>
<td><code>128</code></td>
<td>암호화된 문자열 길이</td>
</tr>
</tbody></table>
<blockquote>
<p>긴 글(게시글 본문, 리뷰 내용 등)은 <code>max_length</code>가 없는 <code>TextField</code>를 쓰는 게 맞습니다.</p>
</blockquote>
<hr>
<h3 id="max_length를-빠뜨리면">max_length를 빠뜨리면?</h3>
<pre><code class="language-python"># 이렇게 쓰면 오류 발생!
name = models.CharField()

# Django가 이렇게 알려줌:
# TypeError: CharField requires a max_length attribute.</code></pre>
<p><code>CharField</code>는 <code>max_length</code> 없이는 아예 실행이 안 됩니다.</p>
<hr>
<h3 id="한-줄-요약-2">한 줄 요약</h3>
<blockquote>
<p><code>max_length</code> = <strong>&quot;이 칸에는 최대 몇 글자까지 쓸 수 있나요?&quot;</strong> 를 Django와 DB에게 알려주는 필수 설정</p>
</blockquote>
<p>궁금한 게 있으면 더 물어보세요! 😊</p>
<hr>
<p>CharField default 옵션이 뭔가요?</p>
<h2 id="default-옵션이란"><code>default</code> 옵션이란?</h2>
<p><code>default</code>는 <strong>아무것도 입력하지 않았을 때 자동으로 채워지는 기본값</strong>을 설정하는 옵션입니다.</p>
<hr>
<h3 id="가장-쉬운-비유-3">가장 쉬운 비유</h3>
<blockquote>
<p>회원가입 폼을 떠올려보세요.</p>
<ul>
<li>국가 선택칸 → 아무것도 안 고르면 자동으로 <strong>&quot;대한민국&quot;</strong> 이 선택됨</li>
<li>등급 칸 → 처음 가입하면 자동으로 <strong>&quot;일반회원&quot;</strong> 으로 설정됨</li>
</ul>
<p>이 &quot;자동으로 채워지는 값&quot;이 바로 <code>default</code>입니다.</p>
</blockquote>
<hr>
<h3 id="코드-1">코드</h3>
<pre><code class="language-python">class User(models.Model):

    username = models.CharField(max_length=50)
    # default 없음 → 반드시 값을 넣어야 함

    country = models.CharField(max_length=50, default=&#39;대한민국&#39;)
    # 아무것도 안 입력하면 자동으로 &#39;대한민국&#39; 저장

    grade = models.CharField(max_length=20, default=&#39;일반회원&#39;)
    # 아무것도 안 입력하면 자동으로 &#39;일반회원&#39; 저장</code></pre>
<hr>
<h3 id="db에-실제로-어떻게-저장되나-1">DB에 실제로 어떻게 저장되나?</h3>
<table>
<thead>
<tr>
<th>상황</th>
<th><code>default</code> 없을 때</th>
<th><code>default=&#39;일반회원&#39;</code> 있을 때</th>
</tr>
</thead>
<tbody><tr>
<td>값을 입력함</td>
<td><code>&#39;관리자&#39;</code> 저장</td>
<td><code>&#39;관리자&#39;</code> 저장</td>
</tr>
<tr>
<td>값을 안 입력함</td>
<td>오류 발생</td>
<td><code>&#39;일반회원&#39;</code> 자동 저장</td>
</tr>
</tbody></table>
<hr>
<h3 id="default-값의-종류">default 값의 종류</h3>
<pre><code class="language-python"># 1. 빈 문자열 (가장 많이 씀)
nickname = models.CharField(max_length=50, blank=True, default=&#39;&#39;)

# 2. 특정 문자열
grade = models.CharField(max_length=20, default=&#39;일반회원&#39;)

# 3. 함수로 동적 생성 (호출 가능한 객체)
import uuid
code = models.CharField(max_length=36, default=uuid.uuid4)
# → 저장할 때마다 자동으로 고유한 코드 생성</code></pre>
<hr>
<h3 id="blanktrue와-함께-쓰는-이유"><code>blank=True</code>와 함께 쓰는 이유</h3>
<pre><code>blank=True  →  폼에서 비워도 됨
default=&#39;&#39;  →  비웠을 때 DB에 &#39;&#39; 로 저장

이 두 개를 함께 써야 완전한 &quot;선택 입력 칸&quot;이 완성됨</code></pre><pre><code class="language-python"># CharField 선택 입력 칸의 권장 패턴
nickname = models.CharField(max_length=50, blank=True, default=&#39;&#39;)
#                                          ↑ 폼에서 비워도 됨
#                                                        ↑ 비면 &#39;&#39; 로 저장</code></pre>
<hr>
<h3 id="한-줄-요약-3">한 줄 요약</h3>
<blockquote>
<p><code>default</code> = <strong>&quot;아무것도 입력 안 하면 이 값으로 자동 저장해줘&quot;</strong> 라고 Django에게 알려주는 것</p>
</blockquote>
<p>궁금한 게 있으면 더 물어보세요! 😊</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TEMPLATES['DIRS'] STATICFILES_DIRS ]]></title>
            <link>https://velog.io/@hy_1023/TEMPLATESDIRS-STATICFILESDIRS</link>
            <guid>https://velog.io/@hy_1023/TEMPLATESDIRS-STATICFILESDIRS</guid>
            <pubDate>Tue, 07 Apr 2026 07:15:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hy_1023/post/8abdc297-d39e-4935-8ba2-174253374044/image.png" alt=""></p>
<h2 id="🔑-흐름도-읽는-법">🔑 흐름도 읽는 법</h2>
<p><strong>① 왼쪽 폴더 구조</strong>가 실제 내 컴퓨터에 존재하는 파일들이에요.</p>
<p><strong>② settings.py</strong> 에 두 줄을 등록하는 순간:</p>
<ul>
<li>🟢 <code>templates/</code> 폴더 → Django가 HTML 찾을 때 여기를 봄</li>
<li>🟡 <code>static/</code> 폴더 → Django가 CSS/JS 찾을 때 여기를 봄</li>
</ul>
<p><strong>③ 브라우저가 요청하면:</strong></p>
<ul>
<li><code>urls.py</code> → <code>views.py</code> 순서로 실행</li>
<li><code>views.py</code>에서 <code>render(request, &#39;base.html&#39;)</code> 호출</li>
<li>Django가 <strong>설정에 등록된 경로</strong>를 뒤져서 파일을 찾음</li>
</ul>
<hr>
<h2 id="💡-가장-쉬운-비유">💡 가장 쉬운 비유</h2>
<blockquote>
<p><strong>settings.py</strong> = 지도 앱에 즐겨찾기 등록하는 것</p>
<ul>
<li><code>TEMPLATES[&#39;DIRS&#39;]</code> = &quot;HTML은 이 동네에 있어&quot;</li>
<li><code>STATICFILES_DIRS</code> = &quot;CSS/JS는 저 동네에 있어&quot;</li>
</ul>
<p>등록을 안 하면 Django가 <strong>길을 몰라서 파일을 못 찾음</strong> → 오류!</p>
</blockquote>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/9fa1e945-e2cf-4426-be91-5cd3dbcbbe15/image.png" alt=""></p>
<h2 id="django-설정-2번-3번-개념-설명">Django 설정 2번, 3번 개념 설명</h2>
<p><strong><code>TEMPLATES[&#39;DIRS&#39;]</code></strong> 는 Django에게 HTML 파일을 어디서 찾아야 하는지 알려주는 설정이고, <strong><code>STATICFILES_DIRS</code></strong> 는 CSS, JS, 이미지 같은 정적 파일을 어디서 찾아야 하는지 알려주는 설정입니다. 두 설정 모두 &quot;파일 탐색 경로&quot;를 지정하는 역할을 합니다.</p>
<p>아래 흐름도로 전체 구조를 확인해 보세요.---</p>
<h2 id="django-설정-2번-3번-개념-설명-1">Django 설정 2번, 3번 개념 설명</h2>
<p><strong><code>TEMPLATES[&#39;DIRS&#39;]</code></strong> 는 Django에게 HTML 파일을 어디서 찾아야 하는지 알려주는 설정이고, <strong><code>STATICFILES_DIRS</code></strong> 는 CSS, JS, 이미지 같은 정적 파일을 어디서 찾아야 하는지 알려주는 설정입니다. 두 설정 모두 &quot;파일 탐색 경로&quot;를 지정하는 역할을 합니다.</p>
<p>아래 흐름도로 전체 구조를 확인해 보세요.---</p>
<h2 id="2️⃣-templatesdirs--html-찾는-경로">2️⃣ <code>TEMPLATES[&#39;DIRS&#39;]</code> — HTML 찾는 경로</h2>
<pre><code class="language-python">&#39;DIRS&#39;: [BASE_DIR / &#39;templates&#39;]</code></pre>
<p><strong>역할:</strong> Django가 <code>render(request, &#39;base.html&#39;)</code> 같은 코드를 만났을 때, HTML 파일을 어느 폴더에서 찾아야 하는지 알려줍니다.</p>
<p><strong>흐름:</strong></p>
<ol>
<li><code>views.py</code>에서 <code>render(request, &#39;index.html&#39;)</code> 호출</li>
<li>Django가 <code>TEMPLATES[&#39;DIRS&#39;]</code>에 등록된 경로를 순서대로 탐색</li>
<li><code>프로젝트루트/templates/index.html</code> 발견 → 렌더링</li>
<li>완성된 HTML을 브라우저에 응답</li>
</ol>
<pre><code>myproject/
├── templates/         ← 이 폴더를 Django가 탐색함
│   ├── base.html
│   └── index.html</code></pre><hr>
<h2 id="3️⃣-staticfiles_dirs--cssjs이미지-찾는-경로">3️⃣ <code>STATICFILES_DIRS</code> — CSS/JS/이미지 찾는 경로</h2>
<pre><code class="language-python">STATICFILES_DIRS = [BASE_DIR / &#39;static&#39;]</code></pre>
<p><strong>역할:</strong> CSS, JavaScript, 이미지 같은 <strong>정적 파일</strong>을 어느 폴더에서 찾아야 하는지 알려줍니다. HTML과 달리 렌더링 없이 파일 자체를 그대로 브라우저에 보냅니다.</p>
<p><strong>흐름:</strong></p>
<ol>
<li>브라우저가 <code>&lt;link rel=&quot;stylesheet&quot; href=&quot;/static/style.css&quot;&gt;</code> 요청</li>
<li>Django가 <code>STATICFILES_DIRS</code>에 등록된 경로를 탐색</li>
<li><code>프로젝트루트/static/style.css</code> 발견 → 파일 그대로 전송</li>
</ol>
<pre><code>myproject/
├── static/            ← 이 폴더를 Django가 탐색함
│   ├── style.css
│   ├── app.js
│   └── logo.png</code></pre><hr>
<h2 id="🔑-핵심-차이-한눈에-비교">🔑 핵심 차이 한눈에 비교</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th><code>TEMPLATES[&#39;DIRS&#39;]</code></th>
<th><code>STATICFILES_DIRS</code></th>
</tr>
</thead>
<tbody><tr>
<td>대상 파일</td>
<td><code>.html</code></td>
<td><code>.css</code>, <code>.js</code>, 이미지</td>
</tr>
<tr>
<td>처리 방식</td>
<td>렌더링 (데이터 삽입)</td>
<td>파일 그대로 전송</td>
</tr>
<tr>
<td>호출 위치</td>
<td><code>views.py</code>에서 <code>render()</code></td>
<td>HTML의 <code>{% static %}</code> 태그</td>
</tr>
<tr>
<td>폴더명 관례</td>
<td><code>templates/</code></td>
<td><code>static/</code></td>
</tr>
</tbody></table>
<p>두 설정 모두 <strong>&quot;Django야, 파일을 여기서 찾아!&quot;</strong> 라고 경로를 등록하는 것이 핵심입니다. 추가로 궁금한 부분 있으면 알려주세요!</p>
<h2 id="2️⃣-templatesdirs--html-찾는-경로-1">2️⃣ <code>TEMPLATES[&#39;DIRS&#39;]</code> — HTML 찾는 경로</h2>
<pre><code class="language-python">&#39;DIRS&#39;: [BASE_DIR / &#39;templates&#39;]</code></pre>
<p><strong>역할:</strong> Django가 <code>render(request, &#39;base.html&#39;)</code> 같은 코드를 만났을 때, HTML 파일을 어느 폴더에서 찾아야 하는지 알려줍니다.</p>
<p><strong>흐름:</strong></p>
<ol>
<li><code>views.py</code>에서 <code>render(request, &#39;index.html&#39;)</code> 호출</li>
<li>Django가 <code>TEMPLATES[&#39;DIRS&#39;]</code>에 등록된 경로를 순서대로 탐색</li>
<li><code>프로젝트루트/templates/index.html</code> 발견 → 렌더링</li>
<li>완성된 HTML을 브라우저에 응답</li>
</ol>
<pre><code>myproject/
├── templates/         ← 이 폴더를 Django가 탐색함
│   ├── base.html
│   └── index.html</code></pre><hr>
<h2 id="3️⃣-staticfiles_dirs--cssjs이미지-찾는-경로-1">3️⃣ <code>STATICFILES_DIRS</code> — CSS/JS/이미지 찾는 경로</h2>
<pre><code class="language-python">STATICFILES_DIRS = [BASE_DIR / &#39;static&#39;]</code></pre>
<p><strong>역할:</strong> CSS, JavaScript, 이미지 같은 <strong>정적 파일</strong>을 어느 폴더에서 찾아야 하는지 알려줍니다. HTML과 달리 렌더링 없이 파일 자체를 그대로 브라우저에 보냅니다.</p>
<p><strong>흐름:</strong></p>
<ol>
<li>브라우저가 <code>&lt;link rel=&quot;stylesheet&quot; href=&quot;/static/style.css&quot;&gt;</code> 요청</li>
<li>Django가 <code>STATICFILES_DIRS</code>에 등록된 경로를 탐색</li>
<li><code>프로젝트루트/static/style.css</code> 발견 → 파일 그대로 전송</li>
</ol>
<pre><code>myproject/
├── static/            ← 이 폴더를 Django가 탐색함
│   ├── style.css
│   ├── app.js
│   └── logo.png</code></pre><hr>
<h2 id="🔑-핵심-차이-한눈에-비교-1">🔑 핵심 차이 한눈에 비교</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th><code>TEMPLATES[&#39;DIRS&#39;]</code></th>
<th><code>STATICFILES_DIRS</code></th>
</tr>
</thead>
<tbody><tr>
<td>대상 파일</td>
<td><code>.html</code></td>
<td><code>.css</code>, <code>.js</code>, 이미지</td>
</tr>
<tr>
<td>처리 방식</td>
<td>렌더링 (데이터 삽입)</td>
<td>파일 그대로 전송</td>
</tr>
<tr>
<td>호출 위치</td>
<td><code>views.py</code>에서 <code>render()</code></td>
<td>HTML의 <code>{% static %}</code> 태그</td>
</tr>
<tr>
<td>폴더명 관례</td>
<td><code>templates/</code></td>
<td><code>static/</code></td>
</tr>
</tbody></table>
<p>두 설정 모두 <strong>&quot;Django야, 파일을 여기서 찾아!&quot;</strong> 라고 경로를 등록하는 것이 핵심입니다. 추가로 궁금한 부분 있으면 알려주세요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[dir]]></title>
            <link>https://velog.io/@hy_1023/dir</link>
            <guid>https://velog.io/@hy_1023/dir</guid>
            <pubDate>Tue, 07 Apr 2026 07:12:14 GMT</pubDate>
            <description><![CDATA[<h1 id="📁-dir-directory--디렉토리란">📁 <code>dir</code> (Directory) — 디렉토리란?</h1>
<h2 id="🔑-핵심-개념">🔑 핵심 개념</h2>
<p><strong>디렉토리(Directory)</strong> 는 파일을 담는 <strong>&quot;폴더&quot;</strong> 입니다.
Windows의 폴더(📂)와 같은 개념으로, 파일과 다른 디렉토리를 <strong>계층적으로 정리·보관</strong>하는 컨테이너입니다.</p>
<hr>
<h2 id="🌳-디렉토리-구조-트리-구조">🌳 디렉토리 구조 (트리 구조)</h2>
<pre><code>/ (루트 디렉토리 — 최상위)
├── home/
│   └── user/
│       ├── documents/
│       │   └── report.txt
│       └── pictures/
│           └── photo.jpg
├── etc/
└── usr/</code></pre><ul>
<li>가장 위에 <strong>루트(<code>/</code>)</strong> 가 있고, 그 아래로 가지처럼 뻗어나갑니다.</li>
<li>디렉토리 안에 디렉토리를 넣을 수 있어서 <strong>중첩 구조</strong>가 가능합니다.</li>
</ul>
<hr>
<h2 id="📌-주요-개념-용어">📌 주요 개념 용어</h2>
<table>
<thead>
<tr>
<th>용어</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>루트 디렉토리</strong></td>
<td>전체 파일 시스템의 시작점 (<code>/</code> 또는 <code>C:\</code>)</td>
</tr>
<tr>
<td><strong>현재 디렉토리</strong></td>
<td>지금 내가 위치한 폴더 (<code>.</code> 으로 표현)</td>
</tr>
<tr>
<td><strong>부모 디렉토리</strong></td>
<td>현재 폴더의 상위 폴더 (<code>..</code> 으로 표현)</td>
</tr>
<tr>
<td><strong>절대 경로</strong></td>
<td>루트부터 전체 경로 (<code>/home/user/docs</code>)</td>
</tr>
<tr>
<td><strong>상대 경로</strong></td>
<td>현재 위치 기준 경로 (<code>./docs</code> 또는 <code>../docs</code>)</td>
</tr>
<tr>
<td><strong>홈 디렉토리</strong></td>
<td>사용자 개인 기본 폴더 (<code>~</code> 로 표현)</td>
</tr>
</tbody></table>
<hr>
<h2 id="🖥️-기본-명령어-linuxmac-기준">🖥️ 기본 명령어 (Linux/Mac 기준)</h2>
<pre><code class="language-bash">pwd          # 현재 디렉토리 경로 출력
ls           # 현재 디렉토리 목록 보기
cd 폴더명     # 디렉토리 이동
cd ..        # 상위 디렉토리로 이동
mkdir 이름   # 새 디렉토리 만들기
rmdir 이름   # 빈 디렉토리 삭제</code></pre>
<blockquote>
<p>Windows에서는 <code>dir</code> 명령어가 <code>ls</code> 와 같은 역할 (현재 디렉토리 내용 출력) 을 합니다.</p>
</blockquote>
<hr>
<h2 id="💡-파일-vs-디렉토리-차이">💡 파일 vs 디렉토리 차이</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>파일</th>
<th>디렉토리</th>
</tr>
</thead>
<tbody><tr>
<td>역할</td>
<td>데이터를 저장</td>
<td>파일/폴더를 담는 그릇</td>
</tr>
<tr>
<td>예시</td>
<td><code>report.txt</code>, <code>photo.jpg</code></td>
<td><code>documents/</code>, <code>home/</code></td>
</tr>
<tr>
<td>내용</td>
<td>텍스트, 이미지 등 실제 데이터</td>
<td>다른 파일/디렉토리의 목록</td>
</tr>
</tbody></table>
<hr>
<h2 id="🎯-한-줄-요약">🎯 한 줄 요약</h2>
<blockquote>
<p><strong>디렉토리 = 파일을 체계적으로 정리하기 위한 &quot;폴더&quot;</strong>
트리 구조로 계층화되어 있으며, 운영체제가 파일을 찾고 관리하는 기본 단위입니다.</p>
</blockquote>
<p>더 궁금한 부분(경로 표현 방식, 특정 OS 명령어 등)이 있으면 말씀해 주세요! 😊</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[🔥Django 기초 - 공부시간 기록기 만들기(1)]]></title>
            <link>https://velog.io/@hy_1023/Django-%EA%B8%B0%EC%B4%88-%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B01</link>
            <guid>https://velog.io/@hy_1023/Django-%EA%B8%B0%EC%B4%88-%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B01</guid>
            <pubDate>Tue, 07 Apr 2026 05:27:32 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.figma.com/design/wDh3su4KrlhkzOM1d7vKBT/Django-%EA%B8%B0%EC%B4%88---%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-2-?node-id=0-1&amp;t=v5jE7SjThGqnU9an-1">https://www.figma.com/design/wDh3su4KrlhkzOM1d7vKBT/Django-%EA%B8%B0%EC%B4%88---%EA%B3%B5%EB%B6%80%EC%8B%9C%EA%B0%84-%EA%B8%B0%EB%A1%9D%EA%B8%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-2-?node-id=0-1&amp;t=v5jE7SjThGqnU9an-1</a></p>
<h4 id="가상환경-설정부터-프로젝트-생성-앱-등록-모델-작성-마이그레이션-admin-확인-url-연결-템플릿과-css-적용-함수형-view를-이용한-목록-페이지-구현까지-아주-자세히-실습합니다">가상환경 설정부터 프로젝트 생성, 앱 등록, 모델 작성, 마이그레이션, admin 확인, URL 연결, 템플릿과 CSS 적용, 함수형 View를 이용한 목록 페이지 구현까지 아주 자세히 실습합니다.</h4>
<table>
<thead>
<tr>
<th>파일</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td>manage.py</td>
<td>Django 명령 실행 진입점</td>
</tr>
<tr>
<td>config/settings.py</td>
<td>프로젝트 전체 설정 파일</td>
</tr>
<tr>
<td>config/urls.py</td>
<td>최상위 URL 연결 파일</td>
</tr>
<tr>
<td>config/wsgi.py</td>
<td>배포용 서버 연결</td>
</tr>
<tr>
<td>config/asgi.py</td>
<td>비동기 서버 연결</td>
</tr>
</tbody></table>
<hr>
<p>manage  관리하다 
config  구성 
setting 환경 </p>
<hr>
<h1 id="프로젝트생성과-앱생성의-차이">프로젝트생성과 앱생성의 차이</h1>
<h3 id="7-django-프로젝트-생성">7. Django 프로젝트 생성</h3>
<p>이제 Django 프로젝트 자체를 생성합니다.</p>
<pre><code>django-admin startproject config .
terminal
</code></pre><p>이 명령어의 의미
초보자 입장에서는 이 명령어가 조금 낯설 수 있습니다.</p>
<pre><code>startproject config .
</code></pre><p>config 는 Django 설정 패키지 이름 (보통 수업 때 mysite로 생성했었습니다!)
마지막 . 은 “현재 폴더에 바로 생성하라”는 뜻
입니다.</p>
<p>즉 지금 작업 중인 study_time_tracker 폴더 안에 Django 프로젝트를 바로 생성하겠다는 의미입니다.</p>
<p>생성 후 구조
study_time_tracker/
├── .venv/
├── config/
│   ├── <strong>init</strong>.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py</p>
<hr>
<h4 id="9-앱-생성">9. 앱 생성</h4>
<p>Django에서는 기능 단위를 앱(App) 으로 나누어 관리합니다.</p>
<p>이번 실습에서는 공부 기록 기능을 담당할 study 앱을 생성합니다.</p>
<pre><code>python manage.py startapp study
</code></pre><p>생성 후 구조는 아래와 비슷합니다.</p>
<p>study/
├── <strong>init</strong>.py
├── admin.py
├── apps.py
├── migrations/
├── models.py
├── tests.py
└── views.py</p>
<hr>
<p>dir 디펙토리 
contrib  기여하다 
auth  인증
contenttypes  콘텐츠 유형
staticfiles   정적 파일
insecure  불안정한
ALLOWED_HOSTS   허용된 호스트
MIDDLE WARE  중간 제품?
security  보안 
common 흔한
Authentication  입증
context 문맥
process 진행 
request   요구
template  보받이
APPLICATION 신청 적용 원서 
&#39;config  구성 
&#39;default 기본  디폴트값 
&#39;ENGINE 기관 차 수단 
VALIDATORS 검증자 
AUTH_PASSWORD_VALIDATORS  인증 비밀번호 검증자
validation 확인 
User  사용자 
Attribute
Similarity 유사성 
Attribute  속성 
Validator 검증인 
Minimum 최소한의<br>Length 길이<br>Validator 검증인 
CommonPasswordValidator  일반 비밀번호 유효성 검사기
NumericPasswordValidator    숫자 비밀번호 유효성 검사기</p>
<p>LANGUAGE_CODE  언어 코드 
TIME_ZONE 시간대</p>
<p>STATICFILES  정적 파일
FIELD  분야 </p>
<hr>
<h1 id="11번까지는-최소한의-세팅">11번까지는 최소한의 세팅</h1>
<h1 id="12번부터-중요">12번부터 중요!</h1>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/397a713f-0090-45a0-b9eb-d8e3fc84dbad/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/5c2c50fd-00e8-4073-9dd8-37adbff6812a/image.png" alt=""></p>
<p>--&gt; 기본적인 기초적인 개념이 필요. </p>
<hr>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/374dd693-1cb5-427e-a675-c18d2d9207b2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/18a356f1-2090-4b8d-a62b-18a635752b31/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/a3eb24b1-4855-4d8d-aa75-77e73d9439a5/image.png" alt=""></p>
<hr>
<p>CATEGORY  범주 
algorithm 연산 
verbose 말 수가 많은
PositiveInteger  양의 정수
ordering 주문 
verbose_name 
plural  복수의
return  반환하다<br>property  재산 소유하다 
import  수입<br>blank 공백</p>
<hr>
<h2 id="1️⃣-무엇을-담을까-생각하는-법">1️⃣ &quot;무엇을 담을까&quot; 생각하는 법</h2>
<p>모델을 설계할 때는 코드보다 <strong>&quot;이 서비스가 기억해야 할 정보가 뭔가?&quot;</strong> 를 먼저 생각합니다.</p>
<pre><code>공부 기록 앱이 기억해야 할 것들을 메모지에 적듯이 나열

→ 무슨 공부를 했나?        (title)
→ 어떤 카테고리인가?       (category)
→ 언제 공부했나?           (study_date)
→ 몇 시간 했나?            (hours / minutes)
→ 메모할 게 있나?          (memo)
→ 언제 이 기록을 만들었나? (created_at)
→ 마지막으로 수정한 건?    (updated_at)</code></pre><p>이렇게 <strong>자연어로 먼저 나열</strong>한 다음, 각 항목에 맞는 필드 타입을 골라 코드로 옮기는 순서입니다.</p>
<hr>
<h2 id="2️⃣-modelspy-큰-구조---">2️⃣ models.py 큰 구조---</h2>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/dc9377f4-e31f-4968-a770-a647a47d3648/image.png" alt=""></p>
<h2 id="3️⃣-코드-한-줄씩-해석">3️⃣ 코드 한 줄씩 해석</h2>
<h3 id="①-선택지-상수-category_choices">① 선택지 상수 <code>CATEGORY_CHOICES</code></h3>
<pre><code class="language-python">CATEGORY_CHOICES = [
    (&#39;python&#39;, &#39;Python&#39;),
    (&#39;django&#39;, &#39;Django&#39;),
]
# (&#39;DB에 저장되는 값&#39;, &#39;화면에 보이는 값&#39;)
# DB엔 &#39;python&#39; 저장, 사용자 눈엔 &#39;Python&#39; 표시</code></pre>
<h3 id="②-필드-정의">② 필드 정의</h3>
<pre><code class="language-python">title = models.CharField(max_length=200, verbose_name=&#39;공부 제목&#39;)
#                         ↑ 최대 200자    ↑ admin에 표시될 이름

category = models.CharField(
    max_length=30,
    choices=CATEGORY_CHOICES,  # ← 위에서 만든 선택지 연결
    default=&#39;django&#39;,          # ← 기본값
)

study_date = models.DateField(verbose_name=&#39;공부 날짜&#39;)
# 날짜만 저장 (2026-03-12)

hours = models.PositiveIntegerField(default=0)
# 0 이상의 정수만 허용

memo = models.TextField(blank=True)
# 긴 글, 선택 입력

created_at = models.DateTimeField(auto_now_add=True)
# 처음 저장할 때 자동으로 현재 시각 기록, 이후 변경 안 됨

updated_at = models.DateTimeField(auto_now=True)
# 저장할 때마다 자동으로 현재 시각으로 갱신</code></pre>
<h3 id="③-class-meta">③ class Meta</h3>
<pre><code class="language-python">class Meta:
    ordering = [&#39;-study_date&#39;, &#39;-created_at&#39;]
    # 조회 시 최신 날짜순 자동 정렬 (- = 내림차순)</code></pre>
<h3 id="④-__str__">④ <code>__str__</code></h3>
<pre><code class="language-python">def __str__(self):
    return f&#39;{self.title} ({self.study_date})&#39;
# admin 페이지나 shell에서 객체를 출력하면
# &quot;Django ORM 복습 (2026-03-12)&quot; 형태로 보임</code></pre>
<h3 id="⑤-property">⑤ <code>@property</code></h3>
<pre><code class="language-python">@property
def total_minutes(self):
    return self.hours * 60 + self.minutes
# DB에 저장 안 함. 그냥 계산해서 돌려주는 값
# study.total_minutes → 150 (2시간 30분)</code></pre>
<hr>
<h2 id="4️⃣-모델-설계-순서-요약">4️⃣ 모델 설계 순서 요약</h2>
<pre><code>1단계  기억해야 할 정보를 자연어로 나열
          &quot;제목, 날짜, 시간, 메모...&quot;

2단계  각 정보에 맞는 필드 타입 선택
          글자 → CharField / TextField
          숫자 → IntegerField
          날짜 → DateField

3단계  각 필드에 옵션 추가
          필수인지? 기본값은? 최대 길이는?

4단계  Meta, __str__, property 추가
          정렬 방식, 표시 이름, 계산 속성</code></pre><p>이 순서로 생각하면 어떤 모델이든 막히지 않고 작성할 수 있어요! 더 궁금한 부분 있으면 알려주세요 😊</p>
<hr>
<p><code>CharField</code>는 Django 모델에서 가장 자주 쓰는 필드 중 하나로, 짧은 텍스트를 저장하는 칸입니다. 이름, 제목, 주소처럼 한 줄짜리 글자를 담을 때 씁니다.</p>
<p>아래 흐름도로 전체 개념을 한눈에 확인해 보세요.---</p>
<p><img src="https://velog.velcdn.com/images/hy_1023/post/089f8017-9a3a-4a6d-aff2-b413100392f1/image.png" alt=""></p>
<h2 id="핵심-개념-정리">핵심 개념 정리</h2>
<h3 id="charfield--짧은-글자를-저장하는-칸">CharField = &quot;짧은 글자를 저장하는 칸&quot;</h3>
<p>엑셀의 셀 하나라고 생각하면 쉬워요. 이름, 제목, 브랜드명처럼 한 줄짜리 텍스트를 담는 용도입니다.</p>
<pre><code class="language-python">name = models.CharField(max_length=100)</code></pre>
<p>이 한 줄이 DB에 <code>VARCHAR(100)</code> 컬럼 하나를 만들어 줍니다.</p>
<hr>
<h3 id="옵션-설명">옵션 설명</h3>
<table>
<thead>
<tr>
<th>옵션</th>
<th>역할</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>max_length</code></td>
<td>최대 글자 수 (필수!)</td>
<td><code>max_length=100</code></td>
</tr>
<tr>
<td><code>blank=True</code></td>
<td>폼에서 비워도 됨</td>
<td>선택 입력 항목에 사용</td>
</tr>
<tr>
<td><code>null=True</code></td>
<td>DB에 NULL 저장 허용</td>
<td>blank와 함께 쓸 때가 많음</td>
</tr>
<tr>
<td><code>default=&#39;&#39;</code></td>
<td>기본값 설정</td>
<td>아무것도 안 입력하면 이 값</td>
</tr>
</tbody></table>
<blockquote>
<p><code>blank</code>와 <code>null</code>의 차이가 헷갈릴 수 있는데, <code>blank</code>는 <strong>&quot;폼 입력 검증&quot;</strong>, <code>null</code>은 <strong>&quot;DB 저장&quot;</strong> 의 문제입니다.</p>
</blockquote>
<hr>
<h3 id="charfield를-써야-할-때-vs-말아야-할-때">CharField를 써야 할 때 vs 말아야 할 때</h3>
<ul>
<li>써야 할 때: 이름, 제목, 주소, 전화번호처럼 짧은 한 줄 텍스트</li>
<li><code>TextField</code> 써야 할 때: 게시글 본문, 리뷰 내용처럼 길고 제한 없는 텍스트</li>
<li><code>IntegerField</code> 써야 할 때: 나이, 가격처럼 숫자</li>
</ul>
<p>궁금한 옵션이 있으면 다이어그램의 각 박스를 클릭해 더 물어볼 수 있어요! 😊</p>
<hr>
<p>CharField blank 옵션이 뭔가요?</p>
<h2 id="blanktrue-옵션이란"><code>blank=True</code> 옵션이란?</h2>
<p><code>blank</code>는 <strong>폼(Form) 입력 시 이 칸을 비워도 되는지</strong> 를 결정하는 옵션입니다.</p>
<hr>
<h3 id="가장-쉬운-비유">가장 쉬운 비유</h3>
<blockquote>
<p>회원가입 페이지를 떠올려보세요.</p>
<ul>
<li>이름 입력칸 → <strong>필수</strong> (비우면 &quot;이름을 입력해주세요&quot; 오류)</li>
<li>닉네임 입력칸 → <strong>선택</strong> (비워도 통과)</li>
</ul>
<p>이 &quot;선택 칸&quot;을 만들 때 <code>blank=True</code>를 씁니다.</p>
</blockquote>
<hr>
<h3 id="코드-비교">코드 비교</h3>
<pre><code class="language-python">class User(models.Model):
    username = models.CharField(max_length=50)
    # blank 없음 = 기본값이 blank=False
    # → 폼에서 반드시 입력해야 함

    nickname = models.CharField(max_length=50, blank=True)
    # → 폼에서 비워도 통과됨</code></pre>
<hr>
<h3 id="blank-vs-null-차이-자주-헷갈리는-부분"><code>blank</code> vs <code>null</code> 차이 (자주 헷갈리는 부분!)</h3>
<table>
<thead>
<tr>
<th>옵션</th>
<th>언제 작동하나?</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td><code>blank=True</code></td>
<td>폼 입력할 때</td>
<td>&quot;이 칸 안 채워도 됩니다&quot;</td>
</tr>
<tr>
<td><code>null=True</code></td>
<td>DB에 저장할 때</td>
<td>&quot;DB에 NULL 값 저장 허용&quot;</td>
</tr>
</tbody></table>
<p><code>CharField</code>는 보통 <code>null=True</code> 없이 <code>blank=True</code>만 써도 충분합니다. 비어있을 때 DB에 <code>NULL</code> 대신 빈 문자열 <code>&#39;&#39;</code>을 저장하기 때문입니다.</p>
<pre><code class="language-python"># CharField 권장 패턴
nickname = models.CharField(max_length=50, blank=True, default=&#39;&#39;)
#                                           ↑ 폼 비워도 됨  ↑ 빈 문자열로 저장</code></pre>
<hr>
<h3 id="한-줄-요약">한 줄 요약</h3>
<blockquote>
<p><code>blank=True</code> = <strong>&quot;이 항목은 선택 입력입니다&quot;</strong> 라고 Django에게 알려주는 것</p>
</blockquote>
<p>추가로 궁금한 옵션 있으면 알려주세요! 😊</p>
<hr>
<p>CharField null 옵션이 뭔가요?</p>
<h2 id="nulltrue-옵션이란"><code>null=True</code> 옵션이란?</h2>
<p><code>null</code>은 <strong>DB(데이터베이스)에 저장할 때 &quot;값 없음&quot;을 NULL로 저장할지</strong> 를 결정하는 옵션입니다.</p>
<hr>
<h3 id="가장-쉬운-비유-1">가장 쉬운 비유</h3>
<blockquote>
<p>엑셀 셀을 떠올려보세요.</p>
<ul>
<li>셀에 <strong>빈 문자열</strong> <code>&#39;&#39;</code> 저장 → 셀이 존재하는데 내용이 없는 것</li>
<li>셀에 <strong>NULL</strong> 저장 → 셀 자체에 &quot;아무 값도 없음&quot; 표시</li>
</ul>
<p>이 두 가지는 DB 입장에서 <strong>다른 값</strong>입니다.</p>
</blockquote>
<hr>
<h3 id="코드-비교-1">코드 비교</h3>
<pre><code class="language-python">class User(models.Model):

    nickname = models.CharField(max_length=50, blank=True)
    # null=True 없음 → 비어있으면 DB에 &#39;&#39; (빈 문자열) 저장

    bio = models.CharField(max_length=200, blank=True, null=True)
    # null=True 있음 → 비어있으면 DB에 NULL 저장</code></pre>
<hr>
<h3 id="db에-실제로-어떻게-저장되나">DB에 실제로 어떻게 저장되나?</h3>
<table>
<thead>
<tr>
<th>상황</th>
<th><code>null=True</code> 없을 때</th>
<th><code>null=True</code> 있을 때</th>
</tr>
</thead>
<tbody><tr>
<td>닉네임 입력 안 함</td>
<td><code>&#39;&#39;</code> (빈 문자열)</td>
<td><code>NULL</code></td>
</tr>
<tr>
<td>닉네임 입력함</td>
<td><code>&#39;heeyoung&#39;</code></td>
<td><code>&#39;heeyoung&#39;</code></td>
</tr>
</tbody></table>
<hr>
<h3 id="blank-vs-null-한눈에-비교"><code>blank</code> vs <code>null</code> 한눈에 비교</h3>
<pre><code>blank=True   →   폼(화면) 단계에서 작동   →   &quot;입력 안 해도 됨&quot;
null=True    →   DB 저장 단계에서 작동    →   &quot;NULL로 저장 허용&quot;</code></pre><br>

<pre><code>사용자가 폼에 아무것도 안 입력
        ↓
   blank=True?  ─── No ──→  &quot;필수 항목입니다&quot; 오류 발생
        │
       Yes
        ↓
   DB에 저장할 때
   null=True?  ─── No ──→  &#39;&#39; (빈 문자열) 로 저장
        │
       Yes
        ↓
    NULL 로 저장</code></pre><hr>
<h3 id="charfield에서-권장하는-패턴">CharField에서 권장하는 패턴</h3>
<p><code>CharField</code>는 <code>null=True</code>를 <strong>되도록 쓰지 않는 것</strong>이 Django 권장 방식입니다. &quot;값 없음&quot;을 표현하는 방법이 <code>NULL</code>과 <code>&#39;&#39;</code> 두 가지가 생겨서 나중에 조회할 때 혼란스럽기 때문입니다.</p>
<pre><code class="language-python"># 권장
nickname = models.CharField(max_length=50, blank=True, default=&#39;&#39;)

# 비권장 (CharField에서)
nickname = models.CharField(max_length=50, blank=True, null=True)</code></pre>
<blockquote>
<p><code>null=True</code>는 <code>CharField</code>보다 <code>IntegerField</code>, <code>DateField</code> 같은 숫자/날짜 필드에서 더 자연스럽게 씁니다. 숫자 필드는 &quot;값 없음&quot;을 <code>0</code>으로 표현하면 의미가 달라지기 때문입니다.</p>
</blockquote>
<hr>
<h3 id="한-줄-요약-1">한 줄 요약</h3>
<blockquote>
<p><code>null=True</code> = <strong>&quot;이 칸이 비어있을 때 DB에 NULL로 저장해도 됩니다&quot;</strong> 라고 Django에게 알려주는 것</p>
</blockquote>
<p>궁금한 게 있으면 더 물어보세요! 😊</p>
<hr>
<p>CharField max_length 옵션이 뭔가요?</p>
<h2 id="max_length-옵션이란"><code>max_length</code> 옵션이란?</h2>
<p><code>max_length</code>는 <strong>이 칸에 입력할 수 있는 최대 글자 수</strong>를 정하는 옵션입니다. <code>CharField</code>에서 <strong>반드시 써야 하는 필수 옵션</strong>입니다.</p>
<hr>
<h3 id="가장-쉬운-비유-2">가장 쉬운 비유</h3>
<blockquote>
<p>종이 서류의 입력칸을 떠올려보세요.</p>
<ul>
<li>이름 칸 → <code>[ _ _ _ _ _ _ _ _ _ _ ]</code> (10칸)</li>
<li>주소 칸 → <code>[ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ]</code> (20칸)</li>
</ul>
<p><code>max_length</code>는 이 <strong>칸의 크기</strong>를 정하는 것입니다.</p>
</blockquote>
<hr>
<h3 id="코드">코드</h3>
<pre><code class="language-python">class User(models.Model):
    username = models.CharField(max_length=50)
    # 최대 50글자까지만 저장 가능

    email = models.CharField(max_length=200)
    # 최대 200글자까지 저장 가능</code></pre>
<hr>
<h3 id="max_length가-하는-일-2가지">max_length가 하는 일 2가지</h3>
<pre><code>max_length=50 설정 시

① DB 테이블 생성할 때
   → VARCHAR(50) 컬럼으로 만들어짐
   → DB 자체에서 50자 초과 저장 차단

② 폼(화면) 입력할 때
   → 51자 이상 입력하면 &quot;이 필드의 최대 길이는 50입니다&quot; 오류 발생
   → Django가 자동으로 검증해줌</code></pre><hr>
<h3 id="적절한-max_length-값-가이드">적절한 max_length 값 가이드</h3>
<table>
<thead>
<tr>
<th>저장할 내용</th>
<th>권장 값</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>이름, 닉네임</td>
<td><code>50</code></td>
<td>대부분 50자 이내</td>
</tr>
<tr>
<td>이메일 주소</td>
<td><code>200</code></td>
<td>이메일 최대 길이 규격</td>
</tr>
<tr>
<td>제목, 상품명</td>
<td><code>100~200</code></td>
<td>여유 있게 설정</td>
</tr>
<tr>
<td>주소</td>
<td><code>255</code></td>
<td>긴 주소 대비</td>
</tr>
<tr>
<td>비밀번호(해시)</td>
<td><code>128</code></td>
<td>암호화된 문자열 길이</td>
</tr>
</tbody></table>
<blockquote>
<p>긴 글(게시글 본문, 리뷰 내용 등)은 <code>max_length</code>가 없는 <code>TextField</code>를 쓰는 게 맞습니다.</p>
</blockquote>
<hr>
<h3 id="max_length를-빠뜨리면">max_length를 빠뜨리면?</h3>
<pre><code class="language-python"># 이렇게 쓰면 오류 발생!
name = models.CharField()

# Django가 이렇게 알려줌:
# TypeError: CharField requires a max_length attribute.</code></pre>
<p><code>CharField</code>는 <code>max_length</code> 없이는 아예 실행이 안 됩니다.</p>
<hr>
<h3 id="한-줄-요약-2">한 줄 요약</h3>
<blockquote>
<p><code>max_length</code> = <strong>&quot;이 칸에는 최대 몇 글자까지 쓸 수 있나요?&quot;</strong> 를 Django와 DB에게 알려주는 필수 설정</p>
</blockquote>
<p>궁금한 게 있으면 더 물어보세요! 😊</p>
<hr>
<p>CharField default 옵션이 뭔가요?</p>
<h2 id="default-옵션이란"><code>default</code> 옵션이란?</h2>
<p><code>default</code>는 <strong>아무것도 입력하지 않았을 때 자동으로 채워지는 기본값</strong>을 설정하는 옵션입니다.</p>
<hr>
<h3 id="가장-쉬운-비유-3">가장 쉬운 비유</h3>
<blockquote>
<p>회원가입 폼을 떠올려보세요.</p>
<ul>
<li>국가 선택칸 → 아무것도 안 고르면 자동으로 <strong>&quot;대한민국&quot;</strong> 이 선택됨</li>
<li>등급 칸 → 처음 가입하면 자동으로 <strong>&quot;일반회원&quot;</strong> 으로 설정됨</li>
</ul>
<p>이 &quot;자동으로 채워지는 값&quot;이 바로 <code>default</code>입니다.</p>
</blockquote>
<hr>
<h3 id="코드-1">코드</h3>
<pre><code class="language-python">class User(models.Model):

    username = models.CharField(max_length=50)
    # default 없음 → 반드시 값을 넣어야 함

    country = models.CharField(max_length=50, default=&#39;대한민국&#39;)
    # 아무것도 안 입력하면 자동으로 &#39;대한민국&#39; 저장

    grade = models.CharField(max_length=20, default=&#39;일반회원&#39;)
    # 아무것도 안 입력하면 자동으로 &#39;일반회원&#39; 저장</code></pre>
<hr>
<h3 id="db에-실제로-어떻게-저장되나-1">DB에 실제로 어떻게 저장되나?</h3>
<table>
<thead>
<tr>
<th>상황</th>
<th><code>default</code> 없을 때</th>
<th><code>default=&#39;일반회원&#39;</code> 있을 때</th>
</tr>
</thead>
<tbody><tr>
<td>값을 입력함</td>
<td><code>&#39;관리자&#39;</code> 저장</td>
<td><code>&#39;관리자&#39;</code> 저장</td>
</tr>
<tr>
<td>값을 안 입력함</td>
<td>오류 발생</td>
<td><code>&#39;일반회원&#39;</code> 자동 저장</td>
</tr>
</tbody></table>
<hr>
<h3 id="default-값의-종류">default 값의 종류</h3>
<pre><code class="language-python"># 1. 빈 문자열 (가장 많이 씀)
nickname = models.CharField(max_length=50, blank=True, default=&#39;&#39;)

# 2. 특정 문자열
grade = models.CharField(max_length=20, default=&#39;일반회원&#39;)

# 3. 함수로 동적 생성 (호출 가능한 객체)
import uuid
code = models.CharField(max_length=36, default=uuid.uuid4)
# → 저장할 때마다 자동으로 고유한 코드 생성</code></pre>
<hr>
<h3 id="blanktrue와-함께-쓰는-이유"><code>blank=True</code>와 함께 쓰는 이유</h3>
<pre><code>blank=True  →  폼에서 비워도 됨
default=&#39;&#39;  →  비웠을 때 DB에 &#39;&#39; 로 저장

이 두 개를 함께 써야 완전한 &quot;선택 입력 칸&quot;이 완성됨</code></pre><pre><code class="language-python"># CharField 선택 입력 칸의 권장 패턴
nickname = models.CharField(max_length=50, blank=True, default=&#39;&#39;)
#                                          ↑ 폼에서 비워도 됨
#                                                        ↑ 비면 &#39;&#39; 로 저장</code></pre>
<hr>
<h3 id="한-줄-요약-3">한 줄 요약</h3>
<blockquote>
<p><code>default</code> = <strong>&quot;아무것도 입력 안 하면 이 값으로 자동 저장해줘&quot;</strong> 라고 Django에게 알려주는 것</p>
</blockquote>
<hr>
<h2 id="from-djangocontrib-import-admin--django-내장-모듈"><code>from django.contrib import admin</code> — Django 내장 모듈</h2>
<p><code>django.contrib.admin</code>은 Django가 기본 제공하는 <strong>자동 관리자 인터페이스(Admin Site)</strong> 모듈입니다.</p>
<hr>
<h3 id="핵심-개념">핵심 개념</h3>
<p>Django 프로젝트를 만들면 <code>/admin</code> URL에서 데이터베이스를 GUI로 관리할 수 있는 페이지가 자동 생성됩니다. 이걸 가능하게 해주는 게 바로 <code>django.contrib.admin</code>입니다.</p>
<hr>
<h3 id="주요-사용법">주요 사용법</h3>
<p><strong>1. 모델 단순 등록</strong></p>
<pre><code class="language-python">from django.contrib import admin
from .models import Article

admin.site.register(Article)</code></pre>
<p><strong>2. <code>ModelAdmin</code>으로 커스터마이징</strong></p>
<pre><code class="language-python">from django.contrib import admin
from .models import Article

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    list_display = [&#39;id&#39;, &#39;title&#39;, &#39;author&#39;, &#39;created_at&#39;]  # 목록에 표시할 필드
    list_filter = [&#39;author&#39;, &#39;created_at&#39;]                  # 오른쪽 필터 패널
    search_fields = [&#39;title&#39;, &#39;content&#39;]                    # 검색창
    ordering = [&#39;-created_at&#39;]                              # 정렬 기준
    readonly_fields = [&#39;created_at&#39;]                        # 읽기 전용 필드</code></pre>
<hr>
<h3 id="자주-쓰는-modeladmin-옵션-정리">자주 쓰는 <code>ModelAdmin</code> 옵션 정리</h3>
<table>
<thead>
<tr>
<th>옵션</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>list_display</code></td>
<td>목록 페이지에 표시할 컬럼</td>
</tr>
<tr>
<td><code>list_filter</code></td>
<td>사이드바 필터</td>
</tr>
<tr>
<td><code>search_fields</code></td>
<td>검색 대상 필드</td>
</tr>
<tr>
<td><code>ordering</code></td>
<td>기본 정렬 (<code>-</code>는 내림차순)</td>
</tr>
<tr>
<td><code>readonly_fields</code></td>
<td>수정 불가 필드</td>
</tr>
<tr>
<td><code>fields</code></td>
<td>상세 페이지에 표시할 필드 순서</td>
</tr>
<tr>
<td><code>inlines</code></td>
<td>관련 모델을 같은 페이지에 표시</td>
</tr>
<tr>
<td><code>list_per_page</code></td>
<td>페이지당 항목 수 (기본 100)</td>
</tr>
</tbody></table>
<hr>
<h3 id="설정에서-활성화-확인">설정에서 활성화 확인</h3>
<p><code>settings.py</code>의 <code>INSTALLED_APPS</code>에 반드시 포함되어 있어야 합니다:</p>
<pre><code class="language-python">INSTALLED_APPS = [
    &#39;django.contrib.admin&#39;,      # ✅ 어드민
    &#39;django.contrib.auth&#39;,       # 인증
    &#39;django.contrib.contenttypes&#39;,
    ...
]</code></pre>
<p><code>urls.py</code>에도 등록:</p>
<pre><code class="language-python">from django.contrib import admin
from django.urls import path

urlpatterns = [
    path(&#39;admin/&#39;, admin.site.urls),  # /admin 접속 경로
]</code></pre>
<hr>
<h3 id="어드민-계정-생성">어드민 계정 생성</h3>
<pre><code class="language-bash">python manage.py createsuperuser</code></pre>
<p>이후 <code>/admin</code>에 접속하면 등록된 모델을 GUI로 CRUD 할 수 있습니다.</p>
<p>궁금한 부분이 있으면 더 설명해 드릴게요!</p>
<hr>
<h2 id="등록된-모델을-gui로-crud-할-수-있습니다-의미">&quot;등록된 모델을 GUI로 CRUD 할 수 있습니다&quot; 의미</h2>
<hr>
<h3 id="먼저-crud란">먼저 CRUD란?</h3>
<p>데이터를 다루는 <strong>4가지 기본 동작</strong>의 앞글자를 딴 약자입니다.</p>
<table>
<thead>
<tr>
<th>약자</th>
<th>영어</th>
<th>한국어</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><strong>C</strong></td>
<td>Create</td>
<td><strong>생성</strong></td>
<td>게시글 작성</td>
</tr>
<tr>
<td><strong>R</strong></td>
<td>Read</td>
<td><strong>조회</strong></td>
<td>게시글 목록 보기</td>
</tr>
<tr>
<td><strong>U</strong></td>
<td>Update</td>
<td><strong>수정</strong></td>
<td>게시글 내용 수정</td>
</tr>
<tr>
<td><strong>D</strong></td>
<td>Delete</td>
<td><strong>삭제</strong></td>
<td>게시글 삭제</td>
</tr>
</tbody></table>
<hr>
<h3 id="등록된-모델-이란">&quot;등록된 모델&quot; 이란?</h3>
<p><code>admin.py</code>에 <code>register</code>한 모델을 말합니다.</p>
<pre><code class="language-python">admin.site.register(Article)  # Article 모델을 등록</code></pre>
<p>→ 이렇게 등록해야 <code>/admin</code>에서 보입니다.</p>
<hr>
<h3 id="전체-문장-풀이">전체 문장 풀이</h3>
<blockquote>
<p><strong>&quot;브라우저에서 <code>/admin</code> 주소로 들어가면,</strong>
<strong>등록해 놓은 DB 테이블(모델)을</strong>
<strong>코드 한 줄 없이 화면 클릭만으로</strong>
<strong>추가 / 조회 / 수정 / 삭제 할 수 있다&quot;</strong></p>
</blockquote>
<hr>
<h3 id="실제-흐름">실제 흐름</h3>
<pre><code>① 브라우저에서 localhost:8000/admin 접속
        ↓
② 슈퍼유저로 로그인
        ↓
③ 등록된 모델(예: Article) 클릭
        ↓
④ 버튼 클릭으로 CRUD 가능
   - [추가] 버튼 → Create (생성)
   - 목록 확인   → Read   (조회)
   - 항목 클릭   → Update (수정)
   - [삭제] 버튼 → Delete (삭제)</code></pre><hr>
<h3 id="핵심-요약">핵심 요약</h3>
<p>개발자가 <strong>별도의 관리 페이지를 만들지 않아도</strong>, Django가 자동으로 데이터 관리 화면을 만들어 준다는 뜻입니다! 🎉</p>
<hr>
<h2 id="gui-graphical-user-interface">GUI (Graphical User Interface)</h2>
<p><strong>그래픽 사용자 인터페이스</strong> — 즉, <strong>마우스로 클릭하고 눈으로 보면서 사용하는 화면</strong>입니다.</p>
<hr>
<h3 id="cli-vs-gui-비교">CLI vs GUI 비교</h3>
<table>
<thead>
<tr>
<th></th>
<th>CLI</th>
<th>GUI</th>
</tr>
</thead>
<tbody><tr>
<td>풀네임</td>
<td>Command Line Interface</td>
<td>Graphical User Interface</td>
</tr>
<tr>
<td>사용 방식</td>
<td><strong>명령어 타이핑</strong></td>
<td><strong>마우스 클릭 + 시각적 화면</strong></td>
</tr>
<tr>
<td>예시</td>
<td>터미널, 명령 프롬프트</td>
<td>윈도우 탐색기, 카카오톡, 웹사이트</td>
</tr>
</tbody></table>
<hr>
<h3 id="예시로-이해하기">예시로 이해하기</h3>
<p><strong>CLI 방식</strong> (명령어로 데이터 조회):</p>
<pre><code class="language-bash">SELECT * FROM article WHERE id = 1;</code></pre>
<p><strong>GUI 방식</strong> (Django Admin):</p>
<p>→ 브라우저에서 <code>/admin</code> 접속하면 아래처럼 <strong>버튼, 표, 입력창</strong>으로 똑같은 작업을 할 수 있음</p>
<pre><code>┌─────────────────────────────────┐
│  Articles                  [+추가]│
├────┬──────────┬────────────────┤
│ ID │  제목    │    작성자       │
├────┼──────────┼────────────────┤
│  1 │ 안녕하세요│   admin        │
│  2 │ 테스트   │   user1        │
└────┴──────────┴────────────────┘</code></pre><hr>
<h3 id="한마디-요약">한마디 요약</h3>
<blockquote>
<p><strong>CLI</strong> = 코드/명령어로 조작
<strong>GUI</strong> = 눈에 보이는 화면으로 조작</p>
</blockquote>
<p>Django Admin이 GUI라는 건, <strong>코드 없이 브라우저에서 클릭만으로 DB를 관리할 수 있다</strong>는 뜻입니다! 😊</p>
<hr>
<hr>
<h2 id="from-djangocontrib-import-admin-설명"><code>from django.contrib import admin</code> 설명</h2>
<hr>
<h3 id="한-마디로">한 마디로</h3>
<p><strong>&quot;Django가 만들어놓은 관리자 페이지 기능을 가져오는 것&quot;</strong> 이에요!</p>
<hr>
<h2 id="구조-분석">구조 분석</h2>
<pre><code class="language-python">from django.contrib import admin
  ↑       ↑         ↑      ↑
from    django    contrib  admin
가져와  장고에서  내장앱   관리자기능</code></pre>
<hr>
<h2 id="djangocontrib-란">django.contrib 란?</h2>
<pre><code>django
  └── contrib  ← &quot;contributed(기여하다) apps&quot; 의 약자
        ├── admin      → 관리자 페이지
        ├── auth       → 로그인/인증
        ├── sessions   → 세션 관리
        ├── messages   → 메시지 알림
        └── staticfiles → 정적 파일</code></pre><h3 id="한-마디로-1">한 마디로</h3>
<pre><code>Django 가 기본으로
제공하는 내장 앱 모음! 📦
→ 설치 없이 바로 사용 가능!</code></pre><hr>
<h2 id="admin-이-제공하는-것">admin 이 제공하는 것</h2>
<pre><code class="language-python">from django.contrib import admin

# 1. 모델 등록
admin.site.register(Study)

# 2. 커스텀 Admin 클래스
class StudyAdmin(admin.ModelAdmin):
    list_display = [&#39;title&#39;, &#39;category&#39;]

# 3. 데코레이터 방식
@admin.register(Study)
class StudyAdmin(admin.ModelAdmin):
    list_display = [&#39;title&#39;]</code></pre>
<hr>
<h3 id="커스텀-admin-클래스-의미">커스텀 Admin 클래스 의미</h3>
<h4 id="기본-등록-vs-커스텀-등록-비교">기본 등록 vs 커스텀 등록 비교</h4>
<p><strong>기본 등록</strong> - 아무 설정 없이 그냥 등록</p>
<pre><code class="language-python">admin.site.register(Study)</code></pre>
<p>→ <code>/admin</code>에서 Study 목록이 <strong>기본 형태</strong>로만 보임</p>
<p><strong>커스텀 Admin 클래스</strong> - 어떻게 보여줄지 직접 설정</p>
<pre><code class="language-python">class StudyAdmin(admin.ModelAdmin):
    list_display = [&#39;title&#39;, &#39;category&#39;]

admin.site.register(Study, StudyAdmin)  # ← 둘을 연결</code></pre>
<p>→ <code>/admin</code>에서 Study 목록을 <strong>원하는 형태</strong>로 보여줌</p>
<hr>
<h3 id="list_display--title-category-의미"><code>list_display = [&#39;title&#39;, &#39;category&#39;]</code> 의미</h3>
<p><code>/admin</code>의 <strong>목록 페이지에 어떤 컬럼을 표시할지</strong> 지정하는 옵션입니다.</p>
<p><strong>설정 전</strong></p>
<pre><code>┌─────────────────────┐
│ Study object (1)    │   ← 이렇게만 보임
│ Study object (2)    │
└─────────────────────┘</code></pre><p><strong>설정 후</strong></p>
<pre><code>┌──────────────┬──────────────┐
│    title     │   category   │  ← 컬럼이 보임
├──────────────┼──────────────┤
│ Django 공부  │   백엔드      │
│ React 공부   │   프론트엔드  │
└──────────────┴──────────────┘</code></pre><hr>
<h3 id="한마디-요약-1">한마디 요약</h3>
<blockquote>
<p><code>admin.ModelAdmin</code>을 <strong>상속</strong>받아서,
<code>/admin</code> 페이지를 <strong>내가 원하는 대로 커스터마이징</strong>하는 클래스입니다! ✅</p>
</blockquote>
<hr>
<h3 id="데코레이터-방식-adminregisterstudy-의미">데코레이터 방식 <code>@admin.register(Study)</code> 의미</h3>
<hr>
<h3 id="데코레이터란">데코레이터란?</h3>
<p><strong>함수/클래스 위에 <code>@</code>를 붙여서, 추가 동작을 자동으로 실행</strong>시키는 문법입니다.</p>
<hr>
<h3 id="기존-방식-vs-데코레이터-방식-비교">기존 방식 vs 데코레이터 방식 비교</h3>
<p><strong>기존 방식 (2단계)</strong></p>
<pre><code class="language-python"># ① 클래스 정의
class StudyAdmin(admin.ModelAdmin):
    list_display = [&#39;title&#39;, &#39;category&#39;]

# ② 따로 등록
admin.site.register(Study, StudyAdmin)</code></pre>
<p><strong>데코레이터 방식 (1단계)</strong></p>
<pre><code class="language-python"># ① 정의 + 등록을 동시에!
@admin.register(Study)
class StudyAdmin(admin.ModelAdmin):
    list_display = [&#39;title&#39;, &#39;category&#39;]</code></pre>
<hr>
<h3 id="adminregisterstudy-풀이"><code>@admin.register(Study)</code> 풀이</h3>
<pre><code class="language-python">@admin.register(Study)   # ← &quot;Study 모델에 아래 클래스를 연결해서 등록해줘&quot;
class StudyAdmin(admin.ModelAdmin):
    list_display = [&#39;title&#39;, &#39;category&#39;]</code></pre>
<table>
<thead>
<tr>
<th>부분</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>@</code></td>
<td>데코레이터 표시</td>
</tr>
<tr>
<td><code>admin.register</code></td>
<td>등록 동작을 수행하는 함수</td>
</tr>
<tr>
<td><code>(Study)</code></td>
<td>어떤 모델에 연결할지 지정</td>
</tr>
<tr>
<td><code>StudyAdmin</code></td>
<td>어드민 설정 클래스</td>
</tr>
</tbody></table>
<hr>
<h3 id="한마디-요약-2">한마디 요약</h3>
<blockquote>
<p><strong><code>@admin.register(Study)</code></strong> =
<code>admin.site.register(Study, StudyAdmin)</code>을
<strong>자동으로 실행</strong>해주는 축약 문법</p>
</blockquote>
<p>코드가 짧아지고, <strong>모델과 설정 클래스가 한눈에</strong> 보여서 가독성이 좋아집니다! ✅</p>
<h4 id=""></h4>
<hr>
<h2 id="admin-을-import-하면-생기는-것">admin 을 import 하면 생기는 것</h2>
<pre><code>http://localhost:8000/admin

┌─────────────────────────┐
│   Django 관리자 페이지   │
├─────────────────────────┤
│ 📋 Study                │
│   + 추가                │
│   📝 목록보기            │
├─────────────────────────┤
│ 👤 Users                │
│ 🔑 Groups               │
└─────────────────────────┘</code></pre><h3 id="이게-다-자동으로-생성-✅">이게 다 자동으로 생성! ✅</h3>
<hr>
<h2 id="settingspy-와의-관계">settings.py 와의 관계</h2>
<pre><code class="language-python"># settings.py
INSTALLED_APPS = [
    &#39;django.contrib.admin&#39;,     # ← 여기 등록되어 있어야
    &#39;django.contrib.auth&#39;,
    &#39;django.contrib.sessions&#39;,
    ...
]

# 그래야 admin.py 에서
from django.contrib import admin  # 사용 가능! ✅</code></pre>
<hr>
<h2 id="자주-쓰는-contrib-모음">자주 쓰는 contrib 모음</h2>
<pre><code class="language-python"># 관리자 페이지
from django.contrib import admin

# 로그인/인증
from django.contrib.auth.models import User

# 메시지 알림
from django.contrib import messages

# 로그인 필요 데코레이터
from django.contrib.auth.decorators import login_required</code></pre>
<hr>
<h2 id="비유">비유</h2>
<pre><code>django.contrib
= 스마트폰 기본 앱 📱

설치 없이 처음부터
제공되는 앱들!

admin      = 기본 파일관리앱
auth       = 기본 잠금화면
sessions   = 기본 메모리
messages   = 기본 알림</code></pre><hr>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>코드</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>from</code></td>
<td>가져와</td>
</tr>
<tr>
<td><code>django</code></td>
<td>Django 패키지에서</td>
</tr>
<tr>
<td><code>contrib</code></td>
<td>내장 앱 모음에서</td>
</tr>
<tr>
<td><code>admin</code></td>
<td>관리자 기능을</td>
</tr>
<tr>
<td><code>import</code></td>
<td>불러옴</td>
</tr>
</tbody></table>
<blockquote>
<p>💡 <code>admin.py</code> 파일에서
<strong>이 한 줄 없으면 아무것도 못해요!</strong>
Django 앱 만들면 <strong>자동으로 생성</strong>되는
<strong>필수 import</strong> 예요! ✅</p>
</blockquote>
<hr>
<h1 id="from-djangodb-import-models--django-내장-모듈"><code>from django.db import models</code> — Django 내장 모듈</h1>
<p>이건 Django가 기본으로 제공하는 <strong>내장 모듈</strong>입니다.</p>
<hr>
<h2 id="역할">역할</h2>
<p>Django에서 <strong>데이터베이스 모델을 정의</strong>할 때 사용하는 핵심 모듈이에요.</p>
<pre><code class="language-python">from django.db import models

class Study(models.Model):
    title = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)</code></pre>
<hr>
<h2 id="models-안에-들어있는-주요-내장-기능들"><code>models</code> 안에 들어있는 주요 내장 기능들</h2>
<h3 id="📌-필드-field--컬럼-타입-정의">📌 필드 (Field) — 컬럼 타입 정의</h3>
<pre><code class="language-python">models.CharField()        # 짧은 문자열
models.TextField()        # 긴 문자열
models.IntegerField()     # 정수
models.FloatField()       # 실수
models.BooleanField()     # True/False
models.DateField()        # 날짜
models.DateTimeField()    # 날짜+시간
models.EmailField()       # 이메일
models.ImageField()       # 이미지 파일
models.FileField()        # 파일
models.ForeignKey()       # 1:N 관계
models.ManyToManyField()  # N:N 관계
models.OneToOneField()    # 1:1 관계</code></pre>
<h3 id="📌-model-클래스--테이블-정의">📌 Model 클래스 — 테이블 정의</h3>
<pre><code class="language-python">class Study(models.Model):  # 이걸 상속받아야 DB 테이블이 됨
    ...</code></pre>
<h3 id="📌-meta-옵션--모델-설정">📌 Meta 옵션 — 모델 설정</h3>
<pre><code class="language-python">class Study(models.Model):
    class Meta:
        ordering = [&#39;-created_at&#39;]   # 기본 정렬
        db_table = &#39;my_study&#39;        # 테이블 이름 지정
        verbose_name = &#39;스터디&#39;       # 관리자 페이지 표시명</code></pre>
<hr>
<h2 id="자주-쓰는-django-내장-import-모음">자주 쓰는 Django 내장 import 모음</h2>
<pre><code class="language-python"># DB 모델
from django.db import models

# 뷰
from django.shortcuts import render, redirect, get_object_or_404

# URL
from django.urls import path, include

# 인증
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required

# 폼
from django.forms import ModelForm

# 설정
from django.conf import settings</code></pre>
<hr>
<p><strong>핵심 요약:</strong> <code>from django.db import models</code>는 Django가 설치될 때 함께 제공되는 <strong>내장 모듈</strong>이고, 이걸 통해 Python 클래스를 DB 테이블로 변환할 수 있어요! 🎯</p>
]]></description>
        </item>
    </channel>
</rss>