meong_j
기록하는 습관.
meong_j
전체 방문자
오늘
어제
  • 분류 전체보기 (176)
    • 개인 공부 정리 (0)
    • 서버 운영 (37)
      • Linux (36)
    • Frontend (11)
      • Vue.js (10)
    • Backend (70)
      • Java (4)
      • Python (22)
      • Django (38)
      • Spring (6)
    • Database (5)
      • Oracle (4)
      • MySQL (1)
      • MariaDB (0)
    • Android (14)
      • Kotlin (6)
    • 배포 (9)
      • Docker (8)
      • AWS (1)
    • IT_study (29)
      • Coding test (17)
      • 알고리즘 (5)
      • 스터디 (6)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • github

인기 글

반응형

태그

  • docker
  • DHCP
  • dp #알고리즘
  • 중첩라우트
  • 배포인프라
  • SASS Variables
  • dockersecret
  • cpu사용률
  • 안드로이드adaptor
  • Proxy
  • Kotlin
  • 개발자도서
  • 이차원배열정렬
  • 코틀린자료형
  • gabagecollecter
  • 테크커리어
  • 리눅스방화벽
  • 리눅스인증
  • django
  • router-link

최근 댓글

최근 글

250x250
hELLO · Designed By 정상우.
meong_j

기록하는 습관.

django 23. Articleapp 구현
Backend/Django

django 23. Articleapp 구현

2021. 10. 10. 22:32
728x90
반응형

models.py

from django.contrib.auth.models import User
from django.db import models


class Article(models.Model):
    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)
  • article model 정의
  • writer 필드는 User 탈퇴시에도 게시글은 삭제되지 않음 (SET_NULL)
  • 이미지는 article/ 경로 밑에 저장 하고 항상 넣도록 하기(null=False)
  • 데이터 생성 시 자동으로 생성시간 저장됨(auto_now_add=True)

 

forms.py

from django.forms import ModelForm

from articleapp.models import Article


class ArticleCreationForm(ModelForm):
    class Meta:
        model = Article
        fields = ['title', 'image', 'content']
  • modelform 추가
  • title, image, content 필드 구성

 

마이그레이션

python manage.py makemigrations
python manage.py migrate
  • 생성한 model DB에 반영

 

urls.py

from django.urls import path

from django.views.generic import TemplateView

from articleapp.views import ArticleCreateView, ArticleDetailView, ArticleUpdateView, ArticleDeleteView

app_name = 'articleapp'

urlpatterns = [
    path('list/', TemplateView.as_view(template_name='articleapp/list.html'), name='list'),
    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'),
]
  • app_name 추가
  • create, detail, update, delete url 지정

 

views.py

from _testcapi import get_kwargs
from django.urls import reverse, reverse_lazy
from Tools.scripts.texi2html import kwprog
from django.contrib.auth.decorators import login_required

from django.shortcuts import render

# Create your views here.
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


# login_required : 게시물 작성 시 항상 로그인되어 있어야함
@method_decorator(login_required(), 'get')
@method_decorator(login_required(), 'post')
class ArticleCreateView(CreateView):
    model = Article
    form_class = ArticleCreationForm
    template_name = 'articleapp/create.html'

    # 서버에서 writer 지정
    def form_valid(self, form):
        # 같은 writer와 로그인한 user인지 체크
        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
    context_object_name = 'target_article'
    form_class = ArticleCreationForm
    template_name = 'articleapp/update.html'

    def get_success_url(self):
        # 성공시 detail.html로 이동
        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'
  • createview, detailview, updateview, deleteview 추가
  • login_required()는 게시물 작성시 항상 로그인이 되어있음 확인
  • 게시물 작성, 수정, 삭제 후 detail로 이동
  • 내가 만든 article_ownership_required 데코레이터 추가

 

decorators.py

from django.contrib.auth.models import User
from django.http import HttpResponseForbidden

import articleapp
from articleapp.models import Article


def article_ownership_required(func):
    def decorated(request, *args, **kwargs):
        article = Article.objects.get(pk=kwargs['pk'])
        if not article.writer == request.user:
            return HttpResponseForbidden()
        return func(request, *args, **kwargs)
    return decorated
  • article 작성 게시자가 request된 user인지 확인
  • 같은 user가 아니면 forbidden페이지 return

 

 

list.html

{% 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 >
    <img src="https://picsum.photos/200/300">
  </div>
  <div >
    <img src="https://picsum.photos/200/340">
  </div>
  <div >
    <img src="https://picsum.photos/200/260">
  </div>
   <div >
    <img src="https://picsum.photos/200/400">
  </div>
    <div >
    <img src="https://picsum.photos/200/300">
  </div>
    <div >
    <img src="https://picsum.photos/200/250">
  </div>
   <div >
    <img src="https://picsum.photos/200/200">
  </div>
  <div >
    <img src="https://picsum.photos/200/440">
  </div>
    <div >
    <img src="https://picsum.photos/200/300">
  </div>
    <div >
    <img src="https://picsum.photos/200/200">
  </div>
   <div >
    <img src="https://picsum.photos/200/350">
  </div>
   <div >
    <img src="https://picsum.photos/200/430">
  </div>
    <div >
    <img src="https://picsum.photos/200/300">
  </div>
    <div >
    <img src="https://picsum.photos/200/400">
  </div>
    <div >
    <img src="https://picsum.photos/200/280">
  </div>

  </div>

<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>

<script src="{% static 'js/magicgrid.js' %}"></script>

{% endblock %}
  • 게시물 추가할 수 있는 create Article 버튼 추가

  • 생성 버튼 추가된 페이지

 

create.html

{% extends 'base.html' %}
{% load bootstrap4 %}

{% block content %}

<div style="text-align:center;  max-width: 500px; margin: 4rem auto">
    <div class="mb-4">
        <h4>Article Create</h4>
    </div>
    <form action="{% url 'articleapp:create' %}"  method="post" enctype="multipart/form-data">
        {% csrf_token %}
        {% bootstrap_form form %}
        <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
    </form>
</div>


{% endblock %}
  • article 작성 페이지
  • 작성 form 생성 및 url 지정

 

  • 글 작성 페이지

 

 

detail.html

{% extends 'base.html' %}
{% load bootstrap4 %}

{% block content %}

<div>
    <div style="text-align: center; max-width: 500px; margin: 4rem auto;">
        <h1>{{ target_article.title }}</h1>
        
        <img src="{{ target_article.image.url }}" alt="">

        <p>
            {{ target_article.content }}
        </p>

        <a href="{% url 'articleapp:update' pk=target_article.pk %}">
            <p>Update Article</p>
        </a>

         <a href="{% url 'articleapp:delete' pk=target_article.pk %}">
            <p>Delete Article</p>
        </a>
       
    </div>

</div>

{% endblock %}
  • 게시물의 title, 이미지, 내용 보여주는 detail 페이지
  • 수정, 삭제 버튼 추가

 

  • 작성한 글 보기
  • detail 페이지

 

update.html

{% extends 'base.html' %}
{% load bootstrap4 %}

{% block content %}

<div style="text-align:center;  max-width: 500px; margin: 4rem auto">
    <div class="mb-4">
        <h4>Article Update</h4>
    </div>
    <form action="{% url 'articleapp:update' pk=target_article.pk %}"  method="post">
        {% csrf_token %}
        {% bootstrap_form form %}
        <input type="submit" class="btn btn-dark rounded-pill col-6 mt-3">
    </form>
</div>


{% endblock %}
  • 게시물 수정 페이지
  • 수정 form 및 update url 로 지정

 

delete.html

{% extends 'base.html' %}
{% load bootstrap4 %}

{% block content %}

<div style="text-align:center;  max-width: 500px; margin: 4rem auto">
    <div class="mb-4">
        <h4>Delete Article : {{ target_article.title }}</h4>
    </div>
    <form action="{% url 'articleapp:delete' pk=target_article.pk %}"  method="post">
        {% csrf_token %}
        <input type="submit" class="btn btn-danger rounded-pill col-6 mt-3">
    </form>
</div>


{% endblock %}
  • 게시물 삭제 페이지
  • title, 삭제 버튼 추가

 

  • 글 삭제 페이지
  • 제출 버튼 누르면 글 삭제

 

  • 삭제 후 url 주소로 들어가면 not found error 뜨면서 성공적으로 삭제완료 확인
반응형

'Backend > Django' 카테고리의 다른 글

django 25. Mixin 소개 및 Commentapp 구현  (0) 2021.10.12
django 24. ListView, Pagination 소개 및 적용  (0) 2021.10.10
django 22. MagicGrid 소개 및 Articleapp 시작  (0) 2021.10.10
django 21. get_success_url 함수 그리고 리팩토링  (0) 2021.10.06
django 20. Profileapp 마무리  (0) 2021.10.06
    'Backend/Django' 카테고리의 다른 글
    • django 25. Mixin 소개 및 Commentapp 구현
    • django 24. ListView, Pagination 소개 및 적용
    • django 22. MagicGrid 소개 및 Articleapp 시작
    • django 21. get_success_url 함수 그리고 리팩토링
    meong_j
    meong_j
    #it #개발일기 #개발공부 #개발자 #백앤드 #생각정리 #시간은 실력에 비례한다 #뭐든지 꾸준히 열심히 #오늘의 내가 내일의 나를 만든다

    티스토리툴바