<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>danho-vak.log</title>
        <link>https://velog.io/</link>
        <description>Django 개발자가 되고싶은 사람</description>
        <lastBuildDate>Mon, 15 Feb 2021 18:43:51 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>danho-vak.log</title>
            <url>https://images.velog.io/images/danho-vak/profile/9d6f1055-04dc-4e33-bbed-23fe801e4bed/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. danho-vak.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/danho-vak" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Django 쇼핑몰 만들기-6]]></title>
            <link>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-6</link>
            <guid>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-6</guid>
            <pubDate>Mon, 15 Feb 2021 18:43:51 GMT</pubDate>
            <description><![CDATA[<p>게으른 과거의 나를 미워하며 과거의 한 일을 다시 복기해서 쓰는 내용(4)</p>
<hr>

<h3 id="오늘-한-일">오늘 한 일</h3>
<p><strong>1. Cartapp의 Model을 작성함</strong></p>
<ul>
<li>User와 Cart는 1:1관계임</li>
<li>그 Cart와 CartItem은 1:N관계임</li>
<li>Cart의 모델 클래스 안 메서드에서 장바구니에 담은 상품들의 총 가격을 가져올 수 있음</li>
</ul>
<p><img src="https://images.velog.io/images/danho-vak/post/7490587f-1ef7-4922-997f-e6f6b10c718a/image.png" alt=""></p>
<p>*<em>2. Cartapp의 CRUD를 구현함 *</em></p>
<ul>
<li><p>장바구니에 이미 들어가있는 상품이라면 해당 상품의 수량을 +1</p>
</li>
<li><p>상품 삭제시 체크박스를 통해 선택된 상품 삭제시 request.POST.getlist()로 리스트를 받음</p>
</li>
<li><p>상품 수량을 변경하는 기능도 추가함</p>
<p><img src="https://images.velog.io/images/danho-vak/post/424c9409-657e-4f2c-85f7-54a3f9e3de8f/image.png" alt=""></p>
</li>
</ul>
<hr>


<h3 id="오늘-알게된-내용">오늘 알게된 내용</h3>
<ol>
<li><p>request.POST.getlist(&#39;cart_item_list[]&#39;, None)</p>
<ul>
<li><p>상황은 이렇다.
  list에서 체크된 상품을 선택 삭제하는 기능을 구현하고자 
  script단에서 체크된 상품의 PK를 넘겨주도록 코드를 짰고
  서버에서 request.POST.getlist()로 받으면 될 줄 알았다. 
  근데 왠걸 계속 None이 들어온다고 오류를 뿜었다.<br></p>
</li>
<li><p>해결한 방법
  위 제목처럼 getlist()안에 명시하는 변수명(Script에서 post로 던지는)에 []를 넣어 이건 list다 라고 명시하니 작동했다.</p>
<pre><code>cartapp/view.py

cart_item_list = request.POST.getlist(&#39;cart_item_list[]&#39;, None)

</code></pre></li>
</ul>
</li>
</ol>
<pre><code>cartapp/list.html
// 선택된 장바구니 상품 삭제
  function deleteCartItem(){
      checked_item = isChecked();
      if (checked_item) {
          var result = confirm(&#39;해당 상품을 장바구니에서 제외할까요?&#39;);
          var cart_pk = $(&#39;#target_cart&#39;).val()
          var cart_item_list = []

          if (result) {
              for (var i=0; i&lt;checked_item.length; i++) {
                  cart_item_list.push(checked_item[i].value);
              }

              $.post(&#39;{% url &#39;cartapp:delete&#39; cart_pk=target_cart.pk %}&#39;,
                  {
                      &#39;csrfmiddlewaretoken&#39; : csrftoken,
                      &#39;cart_item_list&#39; : cart_item_list
                  }, function() {
                      alert(&#39;삭제완료!&#39;);
                      location.reload();
              });
          }
      } else {
          alert(&#39;상품을 선택해주세요!&#39;);
      }
  }</code></pre><pre><code>
+ 추가로 찾아본 정보들


[스택오버플로우](https://stackoverflow.com/questions/11190070/django-getlist)에서 어떤 글은

</code></pre><pre><code>    jQuery POST&#39;s arrays with the [] suffix because PHP and some web frameworks
    understand that convention, and re-build the array on the server-side for you automatically.
    Django doesn&#39;t work that way</code></pre><pre><code>
라고 한다. 

   + 해결 할 수 있는 다른 방법

</code></pre><pre><code>    &lt;input type=&quot;text&quot; name=&quot;input[]&quot;&gt;
    &lt;input type=&quot;text&quot; name=&quot;input[]&quot;&gt;
    &lt;input type=&quot;text&quot; name=&quot;input[]&quot;&gt;</code></pre><p>```</p>
<p>이렇게 아에 마크업을 하는 방법도 있다더라</p>
<hr>

<h3 id="고민해야할-부분">고민해야할 부분</h3>
<p><del>오늘 내용에서는 잘 모르겠다.</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django 쇼핑몰 만들기-5]]></title>
            <link>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-5</link>
            <guid>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-5</guid>
            <pubDate>Mon, 15 Feb 2021 09:09:20 GMT</pubDate>
            <description><![CDATA[<p>게으른 과거의 나를 미워하며 과거의 한 일을 다시 복기해서 쓰는 내용(3)</p>
<hr>

<h3 id="오늘-한-일">오늘 한 일</h3>
<p><strong>1. ProductOption부분을 구현함</strong>
이전 포스트에 간략하게 써놓은 productoption 내용을 작성해보겠다.
처음 상품 부분을 구상할 땐 계층적 구조로 상품 옵션을 구현하려고 했으나, 아무래도 무한 계층구조가 마음에 걸려서 방향을 틀었다.</p>
<p>상품 옵션 table의 하나의 레코드는 상위, 하위 옵션을 전부 갖게 했다.</p>
<pre><code>    옵션PK    상품FK    옵션1    옵션2
        1    1    색상    블랙;화이트;그레이
                .
                    .
                    .</code></pre><p>이런식으로.. 
상품이 많아지면 옵션 TABLE이 아주- 아주- 길어지겠지만
아마 의류 쇼핑몰이란 점을 고려한다면 나쁘지 않겠다 싶어 이 방법을 선택했다.</p>
<p>그래서 Product 등록 부분 script단에서 정규표현식을 통한
입력되는 특수문자를 제한했다. (구분자는 &#39;;&#39; 세미콜론으로 지정)</p>
<p><img src="https://images.velog.io/images/danho-vak/post/6d3a7d63-bf08-4e05-a573-2abc61d93438/image.png" alt=""></p>
<p>*<em>2. 상품 정보 수정 기능을 추가했다. *</em>
Product model의 update부분이다.
<img src="https://images.velog.io/images/danho-vak/post/f4f573e7-031e-4c30-8538-54e0aac7816b/image.png" alt="">
쇼핑몰을 구현해본적 없는게 좀 티 날지 모른다... ㅋㅋ;
직접 가격을 때려넣진 않을거같은데 잘 모르니 어쩌겠나 :( 
기존 등록된 상품의 정보를 단순 수정하는 update부분을 추가했고
하단에 이미지 수정으로 넘어가는 버튼을 달아줬다.</p>
<p><strong>3. 상품 이미지들(상세, 썸네일) 수정 기능을 추가했다.</strong>
쇼핑몰을 운영한다면 상품의 썸네일이나 상세이미지를 교체 할 일이 있지 않을까? 싶어 기능을 추가했다.
단, 기존에 내가 만든 model은 썸네일 model 하나, 상세이미지 model하나 였으니 각각 대응하는 update view가 두개가 되는게 싫어
FBV로 하나의 view에서, 들어오는 trigger값에 따라(썸네일이면 &#39;thumbnail&#39;, 상세이미지면 &#39;detail_image&#39;) 해당 object를 가져와 update하기로했다.</p>
<p><img src="https://images.velog.io/images/danho-vak/post/77020d03-9a1f-42fb-949b-db655d908a4c/image.png" alt="">
이미지 수정의 경우 기존 등록된 이미지들에서 더 추가로 이미지를 올릴 수 있게 했고, 체크박스로 특정 이미지들만 삭제도 가능하게 구현했다.</p>
<pre><code>productapp.views.py

def ProductImageChangeView(request, pk):
    if request.method == &#39;POST&#39;:
        object_type = request.POST.get(&#39;object_type&#39;, None)
        target_pk_list = request.POST.getlist(&#39;modal_input_hidden&#39;, None)
        new_image_list = request.FILES.getlist(&#39;modal_input_file&#39;, None)

        if object_type == &#39;thumbnail&#39;:
            target_object = ProductThumbnailImage.objects.filter(p_target_product_id=Product.objects.get(pk=pk))
            for idx, val in enumerate(target_pk_list):
                each_object = target_object.get(pk=val)
                each_object.p_thumbnail.delete()
                each_object.p_thumbnail = new_image_list[idx]
                each_object.save()

        elif object_type == &#39;detail_image&#39;:
            target_object = ProductDetailImage.objects.filter(p_target_product_id=Product.objects.get(pk=pk))
            for idx, val in enumerate(target_pk_list):
                each_object = target_object.get(pk=val)
                each_object.p_detail_image.delete()
                each_object.p_detail_image = new_image_list[idx]
                each_object.save()

        return redirect(&#39;productapp:images&#39;, pk=pk)</code></pre><hr>


<h3 id="오늘-알게된-내용">오늘 알게된 내용</h3>
<p>** 1. input 태그의 속성값이 disabled일 경우 값 전달이 안된다? **
    - 별거 아닌거같은데 이거 때문에 조금 고생했다. 차암나..</p>
<pre><code>    // submit시 disabled 속성 지우는 script
    $(&#39;form&#39;).submit(function(e){
        $(&#39;:disabled&#39;).each(function(e){
                $(this).removeAttr(&#39;disabled&#39;);
           })
    });</code></pre><p>** 2. Script로 정규표현식 구현하기 **
    - 위에 서술한 option부분에 들어간 내용이다. 하나의 컬럼에 텍스트로 옵션 내용을 주르륵 넣고자 &#39;;&#39; 세미콜론으로 구분자를 정해 DB에 집어넣고 split으로 때어내서 쓸 생각이었다.</p>
<pre><code>    // 상품 option 등록시 정규표현식을 통해 세미콜론만 받을 수 있도록 걸러내는 script
    $(&#39;#id_p_product_option_class_2&#39;).keyup(function(e) {
        var optionValueCheck = /[~!@\#$%^&amp;*\()\-=+_&#39;\[\]{}]/gi;
        var optionVal = $(&quot;#id_p_product_option_class_2&quot;);

        if (optionValueCheck.test(optionVal.val())) {
            optionVal.val(optionVal.val().replace(optionValueCheck,&quot;&quot;));
        }
    });</code></pre><hr>

<h3 id="고민해야할-부분">고민해야할 부분</h3>
<ol>
<li>옵션을 이렇게 저장해도 되나?<ul>
<li>하나의 레코드에 하나의 속성은 하나 이상의 값을 가질 수 없다고 배웠다.
  근데 지금 내가 짠 상품 옵션은 엄밀히 말하면 여러개의 속성값을 하나의 컬럼에 때려 넣은게 아닌가? 저장된 값은 사실 텍스트지만.. 이거 왠지 캥긴다.</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django 쇼핑몰 만들기-4]]></title>
            <link>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-4</link>
            <guid>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-4</guid>
            <pubDate>Tue, 19 Jan 2021 10:25:28 GMT</pubDate>
            <description><![CDATA[<p>게으른 과거의 나를 미워하며 과거의 한 일을 다시 복기해서 쓰는 내용(2)</p>
<hr>

<h3 id="오늘-한-일">오늘 한 일</h3>
<p><strong>1. productapp을 만들고 models.py를 작성함</strong>
개인적으로 쇼핑몰을 만들어보는건 처음이라 Model을 정의하는 작업이 너무 어려웠다..
우선, 오픈마캣이 아닌 개인 쇼핑몰을 구상중이기에 판매자는 admin이다.</p>
<p><img src="https://images.velog.io/images/danho-vak/post/53ab043d-4bee-4d34-bd38-4509efcb011b/shopping_mall.png" alt=""></p>
<ul>
<li><p>상품쪽 ERD</p>
<ul>
<li><p>상품 관련</p>
<ol>
<li>상품은 카테고리를 참조함 (카테고리 1:N 상품)</li>
<li>상품은 여러개의 썸네일을 가질 수 있음 (상품 1:N 썸네일)</li>
<li>상품은 여러개의 상세 이미지를 가질 수 있음 (상품 1:N 상세이미지)</li>
<li>상품은 여러개의 옵션을 가질 수 있음 (상품 1:N 옵션)</li>
</ol>
</li>
<li><p>카테고리 관련</p>
<ol>
<li>카테고리는 models.foreignkey(&#39;self&#39;)를 통해 계층구조를 가짐</li>
</ol>
</li>
<li><p>상품 옵션 관련</p>
<ol>
<li>상품 옵션은 하나의 레코드에 상위 옵션과 하위 옵션을 가짐
ex) 상위 옵션 : 색상, 하위 옵션 : 블랙;화이트;그레이...</li>
</ol>
</li>
</ul>
</li>
</ul>
<p>*<em>2. ProductCategory의 Create를 구현함 *</em></p>
<ul>
<li>product Create를 구현하기 위해 먼저 ProductCategory의 Create를 구현했다.
위의 ERD 설명 부분처럼 카테고리는 foreignkey()의 &#39;self&#39;를 줘서 계층구조를 갖는데 이를 통해 대분류, 중분류, 소분류로 카테고리를 작성할 수 있다.</li>
</ul>
<p><strong>3. Product의 Create를 구현함</strong></p>
<ul>
<li>django-multi-form-view를 통해 다중 모델, 다중 form을 처리하는 view를 구현했다. 
하나의 페이지에서 여러 폼을 가져와 Create로직을 처리하는 방법에 대해 한동안 고민했는데, 템플릿 페이지 안에서 {% include %}를 통해 그냥 페이지만 끌어와 하려다
이렇게 하면 각각 model과 form에 대한 CreateView를 작성해야 할거같아 다른 방법을 찾던중 django-multi-form-view 패키지를 설치해 구현하게 되었다.
<del>(패키지에 의존하면 나약한 개발자가 될거같아 이것도 마음에 걸렸으나, 패키지를 잘 쓰는것도 실력이리라 믿기로 했따...)</del></li>
</ul>
<p><img src="https://images.velog.io/images/danho-vak/post/3d3d9698-eac5-401f-9983-31417d5a733f/image.png" alt=""></p>
<pre><code>productapp/views.py


@method_decorator(CHECK_AUTHENTICATION, &#39;dispatch&#39;)
class ProductCreateView(MultiFormView):
    form_classes = {&#39;ProductCreationForm&#39;: ProductCreationForm,
                    &#39;ProductThumbnailCreationForm&#39;: ProductThumbnailCreationForm,
                    &#39;ProductDetailImageCreationForm&#39;: ProductDetailImageCreationForm}

    template_name = &#39;productapp/create/product_create.html&#39;
    success_url = reverse_lazy(&#39;storeapp:index&#39;)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context[&#39;category_list&#39;] = json.dumps(list(ProductCategory.objects.select_related().all().values()),
                                              ensure_ascii=False)
        return context

    def forms_valid(self, forms):
        product = forms[&#39;ProductCreationForm&#39;].save(commit=False)
        thumb_list = self.request.FILES.getlist(&#39;p_thumbnail&#39;, None)
        detail_list = self.request.FILES.getlist(&#39;p_detail_image&#39;, None)

        category_form = ProductCategoryCreationForm({&#39;category_parent&#39;: self.request.POST.get(&#39;category_parent&#39;),
                                                     &#39;category_name&#39;: self.request.POST.get(&#39;category_name&#39;)})

        if category_form.is_valid():  # category form 유효성 체크
            category = category_form.save()

            product.product_category = category
            product.save()

        if thumb_list:  # 썸네일 저장
            for thumb_image in thumb_list:
                new_thumb = ProductThumbnailImage()
                new_thumb.p_target_product_id = product
                new_thumb.p_thumbnail = thumb_image
                new_thumb.save()

        if detail_list:  # 제품 상세 이미지 저장
            for detail_image in detail_list:
                new_detail_image = ProductDetailImage()
                new_detail_image.p_target_product_id = product
                new_detail_image.p_detail_image = detail_image
                new_detail_image.save()

        return super(ProductCreateView, self).forms_valid(forms)</code></pre><hr>

<h3 id="오늘-알게된-내용">오늘 알게된 내용</h3>
<p>*<em>1. django-multi-form-view를 알게 되었고 적용했다! *</em></p>
<p><a href="https://github.com/TimBest/django-multi-form-view">해당 패키지의 github</a></p>
<ul>
<li>view가 너무 길어질거같아 패키지를 설치해 하나의 view에서 다중 form을 처리하게 만들었다. 해당 클래스의 form_classes 필드에 dict 타입으로 form들을 넣어주면 template_name에 설정한 template문서에 form들을 넘겨준다.
다시 POST로 넘어온 데이터들을 forms_valid()를 통해 한번에 validation check를 할 수 있다!! (단, 이게 어떻게 굴러가는지 좀 더 알아보면 좋을듯)</li>
</ul>
<hr>

<h3 id="고민해야할-부분">고민해야할 부분</h3>
<p><strong>1. 카테고리 계층구조의 최대 참조 가능 수를 설정할 방법을 찾지 못함</strong></p>
<ul>
<li>계층구조에서 나는 최대 3단계를 원하는데 지금 구현된 코드는 무한하다..</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django 쇼핑몰 만들기-3]]></title>
            <link>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-3</link>
            <guid>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-3</guid>
            <pubDate>Tue, 19 Jan 2021 05:11:31 GMT</pubDate>
            <description><![CDATA[<p>게으른 과거의 나를 미워하며 과거의 한 일을 다시 복기해서 쓰는 내용(1)</p>
<hr>

<h3 id="오늘-한-일">오늘 한 일</h3>
<p><strong>1. addressapp의 CRUD기능을 추가했다.(CR을 제외한 다른 부분)</strong></p>
<ul>
<li><p>배송지 부분을 기획하며 배송지 목록을 보여주며 동시에 Form으로 생성도 가능하게 하고 싶었다. 따라서 이전에 Create부분을 만들었으니 FormMixin으로 List를 뿌리고 동시에 Form을 던졌다.
<img src="https://images.velog.io/images/danho-vak/post/4c2849aa-79f3-4ef4-8fa3-49344f3a3e6b/image.png" alt=""></p>
</li>
<li><p>또, 배송지 목록에서 선택을 통해
특정한 배송지를 기본 배송지로 설정 또는 삭제 할 수 있게 하고 싶었다. 해당 부분은 jQuery를 이용해 선택된(checked) DOM을 얻고 value(PK)를 view로 넘겨 처리했다.</p>
</li>
</ul>
<pre><code>addressapp/view.py

def set_default_address(request, case):
    # 기존에 기본 주소로 설정되어 있는 레코드 탐색
    before_object = UserAddress.objects.filter(target_user=request.user, is_default=True)

    if before_object:  # 탐색된 레코드가 있다면
        if case == &#39;create&#39;:  # 새로운 배송지 추가시
            if request.POST.get(&#39;is_default&#39;, None) == &#39;checked&#39;:  # 기본 주소 설정 체크박스가 체크되었다면
                before_object.update(is_default=False)  # 해당 레코드의 기본 주소 설정 값을 False로 변경하고 True 반환
                return True
            else:
                return False

        elif case == &#39;update&#39;:  # 기존 배송지 중 기본 배송지로 변경하는 경우
            target_object = UserAddress.objects.filter(pk=request.POST.get(&#39;address_pk&#39;))
            before_object.update(is_default=False)
            target_object.update(is_default=True)
    else:
        return True  # 탐색된 레코드가 없다면(최초 등록의 경우) True 반환</code></pre><ul>
<li>Delete의 경우 DeleteView를 상속받아 CBV로 구현했고
위의 선택기능(jQuery로 선택된 DOM의 PK를 View로 던져서)을 통해 DeleteView가 알아서 처리하게 두었다.</li>
</ul>
<p>요약 : 
    1. addressapp의 list에서 FormMixin을 상속받아 list에서 create할 수 있도록 수정
    2. addressapp의 기본 배송지 설정 로직 추가
    3. addressapp의 배송지 삭제 로직 추가</p>
<hr>

<h3 id="고민해야할-부분">고민해야할 부분</h3>
<p><strong>1. Query를 낭비하지 않는가?</strong></p>
<ul>
<li>기본 배송지 설정 로직이 정상적으로 작동하나.. set_default_address()에서 update()를 두번 호출하기에 query도 두번 날리는게 아닌가 싶다. ORM을 작성할 때 filter()에 select_related()를 붙여 캐시된 QuerySet을 이용하면 어떨까? Django에서 하나의 트랜잭션을 어떻게 처리하는지 이런 고급적인 내용도 찾아보고싶다.</li>
</ul>
<hr>

<p>여담으로 
addressapp에 배송지를 수정하는(Update)는 구현하지 않을 생각이다. <del>(귀찮)</del> 나는 여지껏 인터넷 쇼핑하며 배송지를 수정해본적이 없따... 뭐 그래서...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django 쇼핑몰 만들기-2]]></title>
            <link>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</link>
            <guid>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-2</guid>
            <pubDate>Tue, 19 Jan 2021 04:27:51 GMT</pubDate>
            <description><![CDATA[<p>아.. 블로그 글쓰는게 하루 이틀 밀리니 이거 너무 밀려버렸다...
과거의 나를 미워한다.........
다시 꾸준히 써보자!
꽤 시간이 흐르는 동안 SQLD 합격, 친구의 의뢰(웹 스크래핑)지만 처음으로 개발을 통해 수입이 생겼다!
더 열심히 해서 취업까지 해보자. 서론이 길었으니 바로 본론으로 가보자.</p>
<hr>

<h3 id="오늘-한-일">오늘 한 일</h3>
<p><strong>1. accountapp의 CRUD기능을 추가했다.</strong>
지난 포스트는 accountapp.models.py를 작성했고 CRUD는 이번에 추가했다.</p>
<p>쇼핑몰이니 당연히 회원관련 기능이 있어야 한다. 비회원 주문 로직도 필요하겠다만, 
추후 주문쪽을 개발하며 같이 개발할 예정이다.</p>
<p>우선 view쪽은 CBV(Class Based View)로 generic view를 주로 이용하여 작성했다.
기능은 다음과 같고, 회원 정보를 Update하는 부분은 내일 중으로 추가 예정이다.</p>
<ul>
<li>C : 회원 가입</li>
<li>R : 비밀번호 변경</li>
<li>U : 회원 정보 출력, 개인 정보 출력</li>
<li>D : 회원 탈퇴</li>
<li>etc : 로그인, 로그아웃</li>
</ul>
<br>

<p><strong>2. 배송지를 관리할 addressapp을 생성했고, CR까지 구현했다.</strong>
내가 구상중인 쇼핑몰은 한명의 회원은 여러개의 배송지를 가질 수 있다. ex)네이버 쇼핑
model은 지번, 도로명 같이 저장하고 각각의 배송지는 alias라는 필드로 별칭을 부여할 수 있다.</p>
<p>주소 검색 API는 다음카카오의 우편번호 서비스를 사용하기로 했다.
링크는 <a href="http://postcode.map.daum.net/guide#info">여기</a> 아마 인터넷 쇼핑을 좀 해본 사람은 흔히 봤을 주소 검색창이다.
선정 이유는 아무래도 사용자에게 더 익숙하고(행안부 주소검색은 사실 나도 처음봤다.),
무료이다. 그리고 무엇보다 <del>API secret key를 발급받고 뭐 이런 과정이 없어서 편했다.</del>
<img src="https://images.velog.io/images/danho-vak/post/a352ca9d-59ce-4a06-bff1-49f65ef9f622/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Django 쇼핑몰 만들기-1]]></title>
            <link>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</link>
            <guid>https://velog.io/@danho-vak/Django-%EC%87%BC%ED%95%91%EB%AA%B0-%EB%A7%8C%EB%93%A4%EA%B8%B0-1</guid>
            <pubDate>Sun, 27 Dec 2020 18:57:43 GMT</pubDate>
            <description><![CDATA[<p>개인 포트폴리오로 쇼핑몰을 만들기로 했다.
앞으로 그날 그날 작업한 이력과 새로 알게된 점들을 글로 남기고자 이 시리즈를 시작한다.</p>
<hr>

<h3 id="오늘-한-일">오늘 한 일</h3>
<p><strong>1. 전반적인 쇼핑몰의 ERD를 그렸다.</strong></p>
<p>DB의 구조를 시각화하여 개발하는데 이해를 돕고자,
나중에 포트폴리오 자료에 첨부하려고 그렸다.</p>
<p>ERD를 그리는데 추가적인 소프트웨어를 설치하고 싶지 않아서 
웹으로 그릴 수 있는 <a href="https://www.erdcloud.com/">ERDCloud를</a> 사용했다.</p>
<p><img src="https://images.velog.io/images/danho-vak/post/8f95189e-2dd1-4d95-972b-6ea72b876a1e/shopping_mall.png" alt=""></p>
<ul>
<li>추가로 ERD 그리는 방법에 대해 공부를 더 할 필요가 있겠다 싶었다.</li>
<li>그리고 나중에 테이블명세서 같은 것도 만들어보면 도움이 되지 않을까</li>
</ul>
<br>

<p><strong>2. Project를 생성했고, account app을 생성했다.</strong>
개인적으로 무언가 이름을 짓는걸 꽤 어려워한다. (게임 캐릭터 이름같은...)
아무튼, 쇼핑몰 이름은 STREET99이 될거다. 요즘 브루클린 나인나인을 보니까</p>
<br>

<p><strong>3. accountapp의 models.py와 admin.py를 작성했다.</strong></p>
<ul>
<li>AbstractBaseUser와 BaseUserManager를 상속받아 클래스 메소드를 오버라이딩 하여
커스터마이징을 했다.</li>
<li>이렇게 커스터마이징한 User 모델을 사용하기위해 settings.py에 설정값을 넣어줬고</li>
<li>admin.py에 UserAdmin을 상속받아 화면을 커스터마이징 하였다.</li>
</ul>
<p> <a href="https://gyukebox.github.io/blog/django-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%9C%A0%EC%A0%80-%EB%AA%A8%EB%8D%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0/">여기</a>를 보며 작업했다.</p>
<br>
<hr>

<h3 id="오늘-알게된-내용">오늘 알게된 내용</h3>
<ol>
<li><p>BaseUserManager를 상속받는 UserManager 클래스를 정의하며...
 AbstractBaseUser를 상속받는 User모델에서 내가 추가한 필드들(전화번호, 생년월일)을 
 UserManager의 create_user()와 create_superuser()에 넘겨주는데 막혔었다.
 기존에 내가 만들던 Model들은 단순히 email, username, password가 전부였으니까.</p>
<p> 문제:
 terminal에서 createsuperuser 명령어를 통해 어드민 계정을 생성하는데
 email, username은 잘 받다가 갑자기 date_of_birth라는 내가 user model에 추가한 field가 
 &#39;NOT NULL constraint failed&#39;를 발생하며 명령어가 취소되었다.</p>
 <br>
 해결:
 create_user(), create_superuser()에 

<pre><code> def create_user(self, email, username, password, **extra_fields):
  def create_superuser(self, email, username, password, **extra_fields):</code></pre><p> 와 같이 파라미터로 내가 User Model에서 추가한 fields들을 넘겨주었고
 create_superuser()의 경우 extra_fields.setdefault()를 통해 default값을 직접 지정하여 해결했다.</p>
</li>
</ol>
<br>

<p><em>models.py</em></p>
<pre><code>class UserManager(BaseUserManager):
    def create_user(self, email, username, password, **extra_fields):
            .
                .
                .

        user = self.model(
            email = self.normalize_email(email),
            username = username,
            **extra_fields
        )
            .
            .
            .


    def create_superuser(self, email, username, password, **extra_fields):
        extra_fields.setdefault(&#39;phone_number&#39;, &#39;00000000000&#39;)
        extra_fields.setdefault(&#39;date_of_birth&#39;, &#39;1900-01-01&#39;)
        user = self.create_user(
            email = self.normalize_email(email),
            username = username,
            password = password,
            **extra_fields
        )
            .
            .
            .


class User(AbstractBaseUser):
    objects = UserManager()

    email = models.EmailField(max_length=60, unique=True)
    username = models.CharField(max_length=20, unique=True)
    phone_number = models.CharField(max_length=20)
    date_of_birth = models.DateField(max_length=8)
    created_at = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
            .
            .
            .
</code></pre><hr>

<h3 id="고민해야할-부분">고민해야할 부분</h3>
<ul>
<li>전화번호와 생년월일을 어떻게 전처리하고 저장할지</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVC vs MVT]]></title>
            <link>https://velog.io/@danho-vak/MVC-vs-MVT</link>
            <guid>https://velog.io/@danho-vak/MVC-vs-MVT</guid>
            <pubDate>Mon, 21 Dec 2020 16:12:52 GMT</pubDate>
            <description><![CDATA[<p>웹 개발을 공부하며 자주 들어봤을 MVC패턴과 Django의 MVT패턴의 차이가 궁금했다.
스윽 듣기로는 큰 차이가 없다고들 한다. 정말 그런지 한번 봐보자!</p>
<p>아, Django의 설계 철학도 한번 봐보면 좋을거 같아 <a href="https://docs.djangoproject.com/ko/3.0/misc/design-philosophies/"><strong>링크</strong></a>도 걸어둔다.</p>
<BR>
우선, 각각의 정의를 알아보자.

<p><strong>MVC 패턴이란?</strong>
Model-View-Controller의 약자로 개발을 진행할 때 구성요소를 세가지의 역할로 구분하여 개발하는 개발 방법론이다. 
<img src="https://images.velog.io/images/danho-vak/post/9f0c67bc-c85a-4627-8171-fecdc3f34264/mvc_role_diagram.png" alt="">
<a href="https://m.blog.naver.com/jhc9639/220967034588">위 이미지를 가져온 곳</a></p>
<ul>
<li>Model : 데이터를 처리하며 DB와 상호 작용하는 인터페이스 역할을 하며, 기본적으로 DB의 복잡성에 얽매이지 않고 데이터와 상호작용할 수 있다.<br></li>
<li>View : 웹 응용 프로그램인 브라우저에서 실제 사용자에게 표시되는 프레젠테이션 로직을 처리하여 UI로 나타낸다.<br></li>
<li>Controller : View에서 핸들러의 흐름을 처리하거나 Model의 데이터를 처리하는 로직을 제공한다.</li>
</ul>
<p>  MVC 패턴의 장점과 단점</p>
<ul>
<li>장점 : 유연성이 높고 유지보수가 용이하며 개발자, 디자이너의 작업 영역을 분리할 수 있음</li>
<li>단점 : 프로젝트의 규모가 커질수록 Controller가 거대해지고 Model, View의 의존성을 분리할 수 없기에 유지보수가 점점 어려워진다.</li>
</ul>
<br>


<p><strong>MVT 패턴이란?</strong>
Model-Template-View의 약자로 MVC를 기반으로 한 디자인 패턴</p>
<ul>
<li>Model : MVC패턴의 Model과 마찬가지로 데이터 간의 인터페이스를 담당한다.<br></li>
<li>View : 프레임워크에서 실제 브라우저에 보이는 프레젠테이션 로직을 처리하고 사용자에게 인터페이스를 제공하는 방법을 제어하는 곳<br></li>
<li>Template : MVC의 Controller와 비슷한 역할을 한다. 따라서 View에서 모든 비지니스 로직을 처리하고, Model과 Templates간의 다리 역할을 하기도 함</li>
</ul>
<br>

<h4 id="그래서">그래서</h4>
<p>Django에서의 MVT패턴은
일반적인 MVC패턴과 각각의 패턴이 하는 일은 크게 차이가 없다.</p>
<p>따라서 MVC패턴과 MVT패턴은 넓게 보면 동일하다고 할 수 있다.</p>
<p>하지만, MVT패턴에서는 View에 프레젠테이션 로직이 아닌, 비지니스 로직을 포함시켜야 한다고 주장하는 패턴이다.</p>
<p>또한 기존 MVC패턴에서 Controller에서 처리해야 했던 일부를 Django 프레임워크에서 자동적으로 처리한다.</p>
<p>즉, MVT패턴은 MVC패턴의 입장에서 보면
Model-Template-View(+Controller)의 형태로 구성되어있다고 볼 수 있을거같다.</p>
<p>다만 위에서 언급한 바와 같이 Controller의 역할 일부를 Django에서 처리하기 때문에 종종 생략되는 경우가 있다.</p>
<br>

<p>해당 포스트의 내용은 </p>
<p><a href="https://nitro04.blogspot.com/2020/01/django-mvc-mvt.html#1down">https://nitro04.blogspot.com/2020/01/django-mvc-mvt.html#1down</a></p>
<p><a href="https://m.blog.naver.com/jhc9639/220967034588">https://m.blog.naver.com/jhc9639/220967034588</a></p>
<p>에서 발췌하였다. 너무 좋은 글들이니 한번씩 봐도 좋을거같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Virtualenv란?]]></title>
            <link>https://velog.io/@danho-vak/Virtualenv%EB%9E%80</link>
            <guid>https://velog.io/@danho-vak/Virtualenv%EB%9E%80</guid>
            <pubDate>Thu, 10 Dec 2020 14:46:41 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>python의 가상환경이란, 
작은 python을 새로 설치해서 내가 원하는 모듈만 운용하는 바구니라고 생각하면 된다.</p>
</blockquote>
<p>출처: <a href="https://dgkim5360.tistory.com/entry/python-virtualenv-on-linux-ubuntu-and-windows">https://dgkim5360.tistory.com/entry/python-virtualenv-on-linux-ubuntu-and-windows</a> [개발새발로그]</p>
<p>단박에 이해하기 쉬운 문구가 있어 가져와봤다.</p>
<p><strong>virtualenv는</strong> 시스템에 설치된 python에 영향을 주지 않고 새로운 python 가상 환경을 만들 수 있게 도와준다. 이 가상 환경에서는 python 실행파일, 라이브러리 설치 장소 등이 제공되고
&#39;가상 환경&#39;답게 패키지를 설치해도 기존 시스템에 영향을 주지 않도록 설계되어 있다.</p>
<p>즉, 시스템의 환경과 각각의 프로젝트 환경을 격리하여 
패키지/라이브러리간 version issue 또는 이외의 dependency issue를 차단하고, 
프로젝트에서 사용하는 패키지/라이브러리를 관리하거나 정리하기 수월하게 도와준다.</p>
<hr>
<br>

<p><strong>설치 및 실행</strong>
virtualenv는 python에 포함되어 있지 않기에 따로 설치해줘야 하며,</p>
<pre><code>pip install virtualenv</code></pre><p>를 통해 설치하고
<br></p>
<pre><code>virtualenv 가상환경명</code></pre><p>으로 가상 환경을 만든다.
<br><br>
성공적으로 가상 환경을 만들었다면</p>
<pre><code>가상환경명/Scripts/activate</code></pre><p>다음과 같이 가상 환경을 활성화/비활성화 할 수 있다.</p>
<pre><code>activate로 가상 환경에 진입할 수 있고
deactivate로 가상 환경에서 나올 수 있다.

ex)
C:\User\사용자명\프로젝트dir\가상환경명\Scripts&gt;activate</code></pre><hr>]]></description>
        </item>
    </channel>
</rss>