컴굥일지

[Django Study 11] Articleapp Implementation 본문

프로그래밍 강의/Django

[Django Study 11] Articleapp Implementation

gyong 2022. 4. 26. 00:05
반응형

[MagicGrid 소개 및 Articleapp 시작]

magicgrid: https://github.com/e-oj/Magic-Grid

Lorem Picsum: https://picsum.photos/

Article app 생성

  1. 터미널에 python manage.py startapp articleapp을 입력하여 앱 생성

  2. settings.py파일에 가서 INSTALLED_APPS에 가서 ‘articleapp’ 추가

  3. pragmatic/urls.py에 가서 아래 코드를 작성하여 프로필 페이지로 연결해주는 경로를 생성

     path('articles/', include('articleapp.urls')),
  4. articleapp파일로 가서 urls.py 만들고, app_name 설정한다.

     from django.urls import path
     from django.views.generic import TemplateView
    
     app_name = 'articleapp'
     urlpatterns = [
             #장고에서 기본으로 제공해주는 view로, template만 지정해주면 나머지는 다 만들어준다.
         path('list/', TemplateView.as_view(template_name='articleapp/list.html'), name='list'),
     ]
  5. static/js/magicgrid.js 파일을 만든다. (깃헙의 dist/magic-grid.cjs.js 파일의 내용을 복붙한다.)

  6. list.html을 만든다. (MagicGrid에서 가져오기)

    • item의 내용에는 이미지를 넣는데, Lorem Picsum을 이용하면 랜덤으로 사진을 보내준다.

    • 5번에서 만든 static 파일을 사용하므로 위에 {% load static %}를 넣고, script태그로 js와 연결한다.

      {% extends 'base.html' %}
      {% load static %}
      {% block content %}
      <style>
        .container div {
          width: 250px;
          background-color: antiquewhite;
          display: flex;
          justify-content: center;
          align-items: center;
          border-radius: 1rem;
        }
      
        .container img {
          width:100%;
          border-radius: 1rem;
        }
      </style>
      
        <div class="container">
          <div class="item1">
            <img src="https://picsum.photos/200/380" alt="">
          </div>
          <div class="item2">
            <img src="https://picsum.photos/200/330" alt="">
          </div>
          <div class="item3">
            <img src="https://picsum.photos/200/310" alt="">
          </div>
          <div class="item4">
            <img src="https://picsum.photos/200/400" alt="">
          </div>
          <div class="item5">
            <img src="https://picsum.photos/200/250" alt="">
          </div>
          <div class="item6">
            <img src="https://picsum.photos/200/280" alt="">
          </div>
          <div class="item7">
            <img src="https://picsum.photos/200/300" alt="">
          </div>
          <div class="item8">
            <img src="https://picsum.photos/200/320" alt="">
          </div>
          <div class="item9">
            <img src="https://picsum.photos/200/270" alt="">
          </div>
          <div class="item10">
            <img src="https://picsum.photos/200/300" alt="">
          </div>
          <div class="item11">
            <img src="https://picsum.photos/200/290" alt="">
          </div>
          <div class="item12">
            <img src="https://picsum.photos/200/220" alt="">
          </div>
          <div class="item13">
            <img src="https://picsum.photos/200/240" alt="">
          </div>
        </div>
      
      <script src= "{% static 'js/magicgrid.js' %}"></script>
      {% endblock %}
  7. magicgrid.js 파일 아래에 이 코드를 추가한다.

    • html에서 사진을 불러오는데 걸리는 시간이 있어서 css가 미리 완성된다.

    • 그렇게 되면 디자인이 이상하므로, img가 다 불러와지면 다시 재배치하도록 js코드를 짠다.

      var masonrys = document.getElementsByTagName('img');
      for(let i=0;i<masonrys.length;i++){
        masonrys[i].addEventListener('load',function(){
            magicGrid.positionItems();
        },false);
      }
      
      magicGrid.listen();


[MagicGrid 소개 및 Articleapp 시작]

  1. models.py에서 아래 코드를 작성한다.

     from django.contrib.auth.models import User
     from django.db import models
    
     # Create your models here.
     class Article(models.Model):
         # on_delete=SET_NULL : 나중에 유저가 사라지면, 알수 없음 정도로 표시
             # related_name: user객체에서 접근할 때 사용하는 이름으로 article이라고 해두자
             # ex) user.article
         writer=models.ForeignKey(User, on_delete=models.SET_NULL, 
                                     related_name='article', null=True)
    
         title = models.CharField(max_length=200,null=True)
         image = models.ImageField(upload_to='article/', null=False)
         content = models.TextField(null=True)
    
         created_at = models.DateField(auto_now_add=True, null=True)
  2. forms.py를 작성한다.

     from django.forms import ModelForm
     from articleapp.models import Article
    
     class ArticleCreationForm(ModelForm):
         class Meta:
             model = Article
             fields = ['title', 'image', 'content']
                     #writer는 서버 내에서 정해줄 것이다.
    • accountapp과는 달리, articleapp은 ModelForm을 상속받는다. (profileapp처럼)
    • 상속받은 이후, Meta 클래스 안에 코드를 작성하면 된다.
  3. model을 만들었으니 python manage.py makemigrationspython manage.py migrate를 터미널에 입력한다.

  4. views.py를 작성한다.

     from django.contrib.auth.decorators import login_required
     from django.shortcuts import render
    
     # Create your views here.
     from django.urls import reverse, reverse_lazy
     from django.utils.decorators import method_decorator
     from django.views.generic import CreateView, DetailView, UpdateView, DeleteView
    
     from articleapp.decorators import article_ownership_required
     from articleapp.forms import ArticleCreationForm
     from articleapp.models import Article
    
     @method_decorator(login_required, 'get')
     @method_decorator(login_required, 'post')
     class ArticleCreateView(CreateView):
         model = Article
         form_class = ArticleCreationForm
         template_name = 'articleapp/create.html'
    
         def form_valid(self, form): #서버에서 writer를 form에 저장한다.
             temp_article = form.save(commit=False)
             temp_article.writer = self.request.user
             temp_article.save()
             return super().form_valid(form)
    
         def get_success_url(self):
             return reverse('articleapp:detail', kwargs={'pk':self.object.pk})
    
     class ArticleDetailView(DetailView):
         model = Article
         context_object_name = 'target_article'
         template_name = 'articleapp/detail.html'
    
     @method_decorator(article_ownership_required, 'get')
     @method_decorator(article_ownership_required, 'post')
     class ArticleUpdateView(UpdateView):
         model = Article
         form_class = ArticleCreationForm
         context_object_name = 'target_article'
         template_name = 'articleapp/update.html'
    
         def get_success_url(self):
             return reverse('articleapp:detail', kwargs={'pk':self.object.pk})
    
     @method_decorator(article_ownership_required, 'get')
     @method_decorator(article_ownership_required, 'post')
     class ArticleDeleteView(DeleteView):
         model = Article
         context_object_name = 'target_article'
         success_url = reverse_lazy('articleapp:list')
         template_name = 'articleapp/delete.html'
  5. urls.py를 추가한다.

     path('create/', ArticleCreateView.as_view(), name='create'),
     path('detail/<int:pk>', ArticleDetailView.as_view(), name='detail'),
     path('update/<int:pk>', ArticleUpdateView.as_view(), name='update'),
     path('delete/<int:pk>', ArticleDeleteView.as_view(), name='delete'),
  6. create, detail, update, delete HTML을 만든다.

    • create, update 에서 img를 저장받으므로 enctype을 입력받는다.
    • articleapp과 코드가 유사하므로 자세한 코드는 생략한다. (주소 바꾸고, 버튼 몇 개 추가하면 된다. - 깃허브 링크 : 35강 기준 커밋)


[ListView, Pagination 소개 및 적용]

  • ListView : 여러개의 개체를 한 번에 보여준다. 장고가 기본 제공해준다.
  • Pagination : 페이지를 나누어 주는 것
  1. ArticleListView()를 만든다.

     class ArticleListView(ListView):
         model = Article
         context_object_name = 'article_list'
         template_name = 'articleapp/list.html'
         paginate_by = 10
  2. urls.py에서 임시로 사용하던 템플릿을 ArticleListView로 바꾼다.

     path('list/', ArticleListView.as_view(), name='list'),
  3. list.html을 수정한다.

    • for문을 사용하여 게시글을 나열한다.

    • card.html라는 base를 만들어 include 하여 보여준다.

    • pagination을 위한 html도 include 한다.

      {% if article_list %}
            <div class="container">
                {% for article in article_list %}
                <a href="{% url 'articleapp:detail' pk=article.pk %}">
                                    #card.html에서 사용하는 article이 현재 사용하는 article이다.
                    {% include 'snippets/card.html' with article=article %}
                </a>
                {% endfor %}
            </div>
            <script src="{% static 'js/magicgrid.js' %}"></script>
      
      {% else %}
            <div style="text-align:center">
              <h1>No Articles YET!</h1>
            </div>
      {% endif %}
      
      # 페이지 
        {% include 'snippets/pagination.html' with page_obj=page_obj %}
      
        <div style="text-align:center">
          <a href="{% url 'articleapp:create' %}" class="btn btn-dark rounded-pill col-3 mt-3 mb-3">
            Create Article
          </a>
        </div>
  4. card.html과 pagination.html을 만든다.

     <!-- card.html -->
     <div>
         <img src="{{ article.image.url }}" alt="">
     </div>
     <!-- pagination.html -->
     <div style="text-align: center; margin: 1rem 0;">
    
     <!--    현재 페이지에서 이전 페이지가 있는지 없는지-->
         {% if page_obj.has_previous %}
         <a href="{% url 'articleapp:list' %}?page={{ page_obj.previous_page_number }}"
            class="btn btn-secondary rounded-pill">
             {{ page_obj.previous_page_number }}
         </a>
         {% endif %}
    
         <a href="{% url 'articleapp:list' %}?page={{ page_obj.number }}"
            class="btn btn-secondary rounded-pill active">
             {{ page_obj.number }}
         </a>
    
     <!--    현재 페이지에서 다음 페이지가 있는지 없는지-->
         {% if page_obj.has_next %}
         <a href="{% url 'articleapp:list' %}?page={{ page_obj.next_page_number }}"
            class="btn btn-secondary rounded-pill">
             {{ page_obj.next_page_number }}
         </a>
         {% endif %}
     </div>


[출처] 작정하고 장고! Django Pinterest 따라만들기 : 바닥부터 배포까지

섹션 5. Articleapp Implementation (34강 ~ 36강)

https://www.inflearn.com/course/%EC%9E%A5%EA%B3%A0-%ED%95%80%ED%84%B0%EB%A0%88%EC%8A%A4%ED%8A%B8/dashboard

반응형
Comments