컴굥일지
[Django Study 11] Articleapp Implementation 본문
[MagicGrid 소개 및 Articleapp 시작]
magicgrid: https://github.com/e-oj/Magic-Grid
Lorem Picsum: https://picsum.photos/
Article app 생성
터미널에 python manage.py startapp articleapp을 입력하여 앱 생성
settings.py파일에 가서 INSTALLED_APPS에 가서 ‘articleapp’ 추가
pragmatic/urls.py에 가서 아래 코드를 작성하여 프로필 페이지로 연결해주는 경로를 생성
path('articles/', include('articleapp.urls')),
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'), ]
static/js/magicgrid.js 파일을 만든다. (깃헙의 dist/magic-grid.cjs.js 파일의 내용을 복붙한다.)
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 %}
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 시작]
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)
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 클래스 안에 코드를 작성하면 된다.
model을 만들었으니 python manage.py makemigrations와 python manage.py migrate를 터미널에 입력한다.
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'
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'),
create, detail, update, delete HTML을 만든다.
- create, update 에서 img를 저장받으므로 enctype을 입력받는다.
- articleapp과 코드가 유사하므로 자세한 코드는 생략한다. (주소 바꾸고, 버튼 몇 개 추가하면 된다. - 깃허브 링크 : 35강 기준 커밋)
[ListView, Pagination 소개 및 적용]
- ListView : 여러개의 개체를 한 번에 보여준다. 장고가 기본 제공해준다.
- Pagination : 페이지를 나누어 주는 것
ArticleListView()를 만든다.
class ArticleListView(ListView): model = Article context_object_name = 'article_list' template_name = 'articleapp/list.html' paginate_by = 10
urls.py에서 임시로 사용하던 템플릿을 ArticleListView로 바꾼다.
path('list/', ArticleListView.as_view(), name='list'),
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>
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강)
'프로그래밍 강의 > Django' 카테고리의 다른 글
[Django Study 13] Mobile Responsive Layout (0) | 2022.05.08 |
---|---|
[Django Study 12] Commentapp Implementation (0) | 2022.04.27 |
[Django Study 10] Profileapp Implementation (0) | 2022.04.25 |
[Django Study 09] Authentication 인증시스템 구현과 Decorator (0) | 2022.04.24 |
[Django Study 08] DetailView, UpdateView, DeleteView 를 통한 accoutapp 구현 (0) | 2022.04.20 |