https://itcreator.tistory.com/129

이어서 하기

 

이전버전은 USER는 DB를 만들지 않아도 따로 생성되었음 (물론 커스터마이징 가능하지만 그건 나중에)

이번은 이전설정과 거의 비슷하게 한번 더 앱을 만들어 보고 게시판/댓글 DB 까지 다뤄보기

 

1.  기초설계

1. ctrl + shift + ~ 터미널 창 열어주기

2. board 앱 폴더 생성 및 등록

# root 기준  터미널 명령어

python manage.py startapp <app 이름>

mkdir -p <app 이름>/templates/<app 이름>  # 템플릿 생성

cd  <app 이름>/templates/<app 이름>  # 최하단 까지 이동

touch detail.html form.html index.html

#detail 게시판글 자세히보기  
#form 게시판 작성 폼
#index 게시글 리스트

 

3. urls.py 및 forms.py 생성

# 다시 최상단 으로 돌아와서( 보통 cd .. 3번 하면됨)

Touch <app이름>/urls.py    # (..../<app이름> 으로 들어오는 통로 열어주기)

Touch <app이름>/forms.py   

# Form 이 친구는 왜만드는거임?
   # 1. 유효성 체크 (validation check)
   # 2. HTML 안에 인풋태그 만들기 귀찮 
   # 3. 저장할 때 request.POST에서 일일이 꺼내기 귀찮아서
   # 이런 작업을 Form 하게 만들려고 미리 폴더 생성

 

2.  board  > urls.py 세팅해주기    (앱이름을 board 로 할 경우)

from django.urls import path
from . import views

app_name = 'board'
urlpatterns = [
    # articles/create/
    path('create/', views.create_article, name='create_article'),    # url에 articles/create/으로 접근이 온다면 => views 에 있는 create_article 함수 실행 / 그리고 이 과정을 create_article 이 라고 칭하겠다. 
    # articles/
    path('', views.article_index, name='article_index'),
    # articles/1/
    path('<int:article_pk>/', views.article_detail, name='article_detail'),
    # articles/1/update/
    path('<int:article_pk>/update/', views.update_article, name='update_article'),
    # articles/1/delete/
    path('<int:article_pk>/delete/', views.delete_article, name='delete_article'),

 

 

3. Model 단 (board > models.py)

from django.db import models
from django.conf import settings

class Article(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) # settings.AUTH_USER_MODEL 파이썬이 이렇게 써달래
    title = models.CharField(max_length=100)									# on_delete=models.CASCADE 이게 지워지면 안에 다른것도 다 지워달라 
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Comment(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    content = models.CharField(max_length=200)
    # foreign key 쓰면 필드명에 _id 붙이지 않기.
    # migrate 하면 알아서 뒤에 _id가 붙음
    article = models.ForeignKey(Article, on_delete=models.CASCADE)
    Created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

 

 

3-1 . Form 단 (board > forms.py)

from django import forms
from .models import Article, Comment
class ArticleForm(forms.ModelForm):
    
    class Meta:
        model = Article
        #fields= '__all__'
        exclude = ('user',) # user는 Article의 FK라 article테이블의 user의 키가 
        					# User테이블의 pk값이 없는걸 넣을려고 하면 DB에서 막음 (무결성)
       
class CommentForm(forms.ModelForm):
    content = forms.CharField(min_length=2, max_length=200,
    widget=forms.TextInput(attrs={'autofocus': True})
    )
    class Meta:
        model = Comment
        # fields = ('content',)
        exclude = ('article', 'user')

model. form 끝냈으면 마이그레이트 시작

python manage.py makemigrations board

python manage.py migrate board

 

 

4. Control 단 (board > views.py)

1. 쉬운 버전용 필요한 클래스 import 하기

# 화면구성, 화면이동, 객체를 받거나 없으면 404에러를 터트려줌 (이거 없으면 서버 문제가 아닌데도 500 서버단 에러를 터트림)
from django.shortcuts import render, redirect, get_object_or_404

# get, post등 url 접근 방식에 따라 분류해서 허용하겠다
from django.views.decorators.http import (require_http_methods, require_POST, require_safe, )

# 로그인 상태에만 해당 함수 실행가능
from django.contrib.auth.decorators import login_required

# DB 불러오기
from .models import Article, Comment

# 앞서 만듬 form 불러오기
from .forms import ArticleForm, CommentForm

 

2. create_article 작성

@login_required  # 로그인이 되어야 이 작업가능
@require_http_methods(['GET', 'POST'])  # GET, POST로 들어오는 경우
def create_article(request):   #request 요청 받은 정보 전부 인수로 전달한뒤 함수 실행
    
    if request.method == 'POST': # POST라면(게시글 등록버튼 누를때)
        form = ArticleForm(request.POST) # POST로 쏘는 내용물 채워서 form에 저장
        if form.is_valid():  # 값이 유효하다면
            article = form.save(commit=False) # 잠깐 저장은 하지말아봐  # article부터 만들어야하는데 save를 하면 오류터짐
            article.user = request.user  # 페이징 요청자의 정보를 글작성자의 정보로 넣어줌
            article.save()  # 게시글 저장(내장함수)
            return redirect('board:article_detail', article.pk)   # 글번호와 함께 detail() 함수실행

    else:   # GET으로 왔다면(페이지를 요청할때)
        
        form = ArticleForm()   # form.py에서 만든걸 form으로
    context = {'form': form }    # context에 담아서 
   
    return render(request, 'board/form.html', context)  # form.html로 넘겨줌

 

3. read

@require_safe # get, head 요청만 허용하겠다.
def article_index(request):
    articles = Article.objects.all()   # DB의 article의 모든 값을 articles에 넣어줌
    context = {'articles': articles, }   # 그걸 context에 담아서
    return render(request, 'board/index.html', context)   # index.html로 넘겨줌

@require_safe
def article_detail(request, article_pk):   # 몇번째 게시글인지 알 수 있게 article_pk 받아야함
    article = get_object_or_404(Article, pk=article_pk)  # db에서 객체를 받던가 404를 띄워라! why? DB에 없는걸 요청한다면 니 잘못
    form = CommentForm() # 댓글보여줄려고-> detail.html에 board/_comment_form.html에 form 쓸려고
    context = {     # 게시글 정보와 댓글을 context에 담아서
        'article': article,
        'form': form
    }
    return render(request, 'board/detail.html', context)   # detail.html로 보냄

 

4. update

@login_required  # 로그인 필요
@require_http_methods(['GET', 'POST'])   # GET, POST로 오는 경우
def update_article(request, article_pk):
    article = get_object_or_404(Article, pk=article_pk)   # 받은 번호의 게시글 정보를 DB에서 찾아 article에 넣어줌
   
    if request.user != article.user:			 # 작성자 아니면
        return redirect('board:article_detail', article.pk)    # 게시글 번호와함께 detail.html로 보내버림

    if request.method == 'POST':   # POST인 경우(게시글 수정 버튼을 누를때)
        form = ArticleForm(request.POST, instance=article)  # instance=student 가 없으면 수정이 아니라 새 값으로 저장되어버림 + 이전정보 넣어주기
        if form.is_valid():  # form이 유효하다면
            # 기존에 저장된 user_id 갱신할 필요가 없기때문에 commit=False 필요 X
            article = form.save()   # 저장해서 article에 넣어주기
            return redirect('board:article_detail', article.pk)   # 게시글 번호 주면서 detail() 함수실행
    else:   # get방식이라면 (이 페이지를 요청할때)
        form = ArticleForm(instance=article)   # # instance=student => form에다가 이전 정보 넣기
    context = {'form': form}   # context에 담아서
    return render(request, 'board/form.html', context)   # form.html로 보냄

 

5. Delete

@login_required   # 로그인 필요
@require_POST   # POST인 경우(url로 들어오는거 막겠다/ 제출버튼으로 토큰 던지면서 와라)
def delete_article(request, article_pk):  # 요청받은 정보와 게시글 번호를 주면서
    article = get_object_or_404(Article, pk=article_pk)  # 번호에 맞는 Article DB에서 객체를 꺼내서 article에 주던가 404로 
    if request.user == article.user:   # 요청자와 글쓴이가 같다면 
        article.delete()   	# 게시글 삭제(내장함수) 
        return redirect('board:article_index')   # index로 보내주기
    else:     # 요청자와 글쓴이가 같지않다면
        return redirect('board:article_detail', article.pk)  # 게시글 번호와함께 detail.html로 보냄

 

6. 댓글 (간단하게 CRD만)

@require_POST
def create_comment(request, article_pk):  # 요청 정보와 게시글 번호를 받음
    form = CommentForm(request.POST) # 댓글 제출 버튼시 값들을 form에 넣어줌 
    article = get_object_or_404(Article, pk=article_pk) # 받은 번호의 게시글 정보를 DB에서 찾아 article에 넣어줌

    if form.is_valid():  # form이 유효하다면
       
        comment = form.save(commit=False)    # 완전 저장시 NOT NULL 에러 뜨니까, 직전에 멈춰 주세요.
        comment.article = article       # 여기선 알아서 값 넣어줌
        comment.user = article			 # 여기선 알아서 값 넣어줌
        comment.save()		# 값 저장(내장함수)
    return redirect('board:article_detail', article.pk)  # 게시글 번호 받아서 detail() 함수 실행 
    # comment.article.pk 게시글 번호임

@require_safe # get, head 요청만 허용하겠다.
def article_index(request):   # 요청한값 받음
    articles = Article.objects.all()  Article DB 값 받아서 articles에 넣어줌
    context = {'articles': articles, }   # 그 값을 context 넣고
    return render(request, 'board/index.html', context)  # index.html로 보내줌

@require_safe
def article_detail(request, article_pk):   # 요청정보와 게시글 번호 받음
    article = get_object_or_404(Article, pk=article_pk)  # 받은 번호의 게시글 정보를 DB에서 찾아 article에 넣어줌
    form = CommentForm() # 댓글보여줄려고-> detail.html에 board/_comment_form.html에 form 쓸려고
    context = {
        'article': article,
        'form': form
    }
    return render(request, 'board/detail.html', context)


@login_required
@require_POST
def delete_comment(request, article_pk, comment_pk):
    comment = get_object_or_404(Comment, pk=comment_pk)
    article = get_object_or_404(Article, pk=article_pk) # article.pk 를 쓰기위해서 만듬
    
    if request.user == comment.user:
        comment.delete()
    return redirect('board:article_detail', article.pk)
    
    # article_pk 안쓰는 이유는 사용자를 믿을수없어서.
    # 사용자가 보낸거 _pk 구분한다음  내부적으로 확인해서 믿을하면 .pk 써도 무방

 

 

총정리

@login_required
@require_http_methods(['GET', 'POST'])
def create_article(request):
    
    if request.method == 'POST': 
        form = ArticleForm(request.POST) 
        if form.is_valid():
            article = form.save(commit=False)
            article.user = request.user 
            article.save()
            return redirect('board:article_detail', article.pk)

    else: 
        form = ArticleForm()
    context = {'form': form }
    return render(request, 'board/form.html', context)

@login_required
@require_http_methods(['GET', 'POST'])
def update_article(request, article_pk):
    article = get_object_or_404(Article, pk=article_pk)
    
    if request.user != article.user:
        return redirect('board:article_detail', article.pk)

    if request.method == 'POST':
        form = ArticleForm(request.POST, instance=article)        
        if form.is_valid():
           
            article = form.save()
            return redirect('board:article_detail', article.pk)
    else:
        form = ArticleForm(instance=article)
    context = {'form': form}
    return render(request, 'board/form.html', context)

@login_required
@require_POST
def delete_article(request, article_pk):
    article = get_object_or_404(Article, pk=article_pk)
    if request.user == article.user:
        article.delete()
        return redirect('board:article_index')
    else:
        return redirect('board:article_detail', article.pk)



@require_POST
def create_comment(request, article_pk):
    form = CommentForm(request.POST)
    article = get_object_or_404(Article, pk=article_pk)

    if form.is_valid():
      
        comment = form.save(commit=False) 
       
        comment.article = article
        comment.user = article
        comment.save()
    return redirect('board:article_detail', article.pk)
  

@require_safe 
def article_index(request):
    articles = Article.objects.all()
    context = {'articles': articles, }
    return render(request, 'board/index.html', context)

@require_safe
def article_detail(request, article_pk):
    article = get_object_or_404(Article, pk=article_pk)
    form = CommentForm() 
    context = {
        'article': article,
        'form': form
    }
    return render(request, 'board/detail.html', context)



@login_required
@require_POST
def delete_comment(request, article_pk, comment_pk):
    comment = get_object_or_404(Comment, pk=comment_pk)
    article = get_object_or_404(Article, pk=article_pk)
    
    if request.user == comment.user:
        comment.delete()
    return redirect('board:article_detail', article.pk)

 

+ Recent posts