Chapter3_Assignment_250123.zip
0.60MB


목록

  1. User 앱
    1. 사용자 모델 구현
    2. 회원가입, 로그인, 로그아웃 기능 구현
      1. 회원가입
      2. 로그인
      3. 로그아웃
    3. 사용자 프로필 페이지 구현
  2. Post 앱 (CRUD)
    1. Post 모델 구현
    2. 게시판 기능
      1. 게시글 목록 보기 (Read - List)
      2. 게시글 상세 보기 (Read - Detail)
      3. 게시글 작성 기능 (Create)
      4. 게시글 수정 기능 (Update)
      5. 게시글 삭제 기능 (Delete)
필수앱 구현
1. View (함수 or 클래스 택 1)
2. 기본 템플릿 (base.html, navbar.html, foodter.html)
3. 데이터베이스 (SQLite3)

평가 기준

  • 코드 구조 및 가독성
  • MTV 패턴 준수
  • 기능의 정확성
  • 에러 처리
  • 코드 재사용성
  • DRF 구현 시 RESTful API 설계 원칙 준수

2. Post 앱 (CRUD)

2.1. Post 모델 구현

필드: 제목, 내용, 작성자, 작성일, 수정일
더보기
from django.db import models
from django.conf import settings

# 글 작성하는 모델
class Article(models.Model):
    title = models.CharField(max_length=50) # 제목은 CharField로, 길이는 50자까지
    content = models.TextField()    # 내용은 TextField로, 아무런 제한 없이 마음껏
    created_at = models.DateTimeField(auto_now_add=True)    # 생성일은 자동으로 채워지게끔
    updated_at = models.DateTimeField(auto_now=True)    # 수정일도 자동으로 채워지게끔

    author = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="post")

 

  • # author는 models.ForeignKey로 데려와용
  • # settings.AUTH_USER_MODEL : settings에 정의해놓은 User 모델을 써용
  • # on_delete=models.CASCADE : 연결된 객체(User)가 삭제되면, 참고하고 있는 객체(Post)도 삭제돼용
  • # related_name :외래 키로 연결된 모델에서 역으로 참조할 때 사용할 이름을 post로 할 거예용
  • ## 예를 들면, User 모델에서 작성한 모든 Post 객체를 가져오고 싶으면 user.post.all()처럼 사용할 수 있어용

2.2. 게시판 기능

2.2.1. 게시글 목록 보기 (post_list)

2.2.1.1. urls.py 추가하기

더보기
from django.urls import path
from . import views

app_name = "post"
urlpatterns = [
    path('post-list/', views.post_list, name="post_list"), # 게시글 목록

2.2.1.2. views.py 추가하기

더보기
from django.contrib.auth.decorators import login_required
from .models import Article

# 게시글 목록 보기
# @login_required(login_url="user:login") : 로그인 안 됐으면 login_url로 가세욧
@login_required(login_url="user:login")
def post_list(request):
    post_list = Article.objects.all().order_by("-created_at")   # 글 목록을 최신순으로 보여줌
    context = {"post_list":post_list}
    return render(request, "post/post_list.html", context)  # post_list.html 양식으로 보여줄게용

 

  • @login_required(login_url="user:login")
    • 로그인을 요구하는데, 로그인하지 않았으면 로그인창으로 보내버려요
  • post_list = Article.objects.all().order_by("-created_at")
    • Article 모델에 있는 항목들을 전부 값으로 불러올 거고, 생성일은 최신순으로 정렬해요

2.2.1.3. post_list.html 추가하기

더보기
<!--게시글 목록 보기-->

{% extends "base.html" %}

{% block content %}

<h1><center>Post List</center></h1>

<!--새 게시물 작성 버튼과 인덱스로 돌아가는 버튼-->
<a href="{% url 'post:post_create' %}"><button>Writing a new post</button></a>
<a href="{% url 'index' %}"><button>Back to index</button></a>
<hr>

<!--Article 모델 로직을 토대로, 글 번호, 제목, 작성자, 추가일, 수정일을 for문으로 돌림-->
<!--최신순으로 정렬됨 ".order_by("-created_at")"-->
{% for post in post_list %}
    <a href="{% url 'post:post_detail' post.id%}">
        <h3>[{{ post.id }}] {{ post.title}} </h3>
        <p>Writer : {{ post.author.username }}</p>
        <p>Date of creation_{{ post.created_at }}</p>
        <p>Date of revision_{{ post.updated_at }}</p>
        <hr>
{% endfor %}
{% endblock content %}

2.2.2. 게시글 상세 보기 (post_detail)

2.2.2.1. urls.py 추가하기

더보기
path('<int:id>/', views.post_detail, name="post_detail"), # 게시글 상세 보기

2.2.2.2. views.py 추가하기

더보기
# 게시글 상세 보기
# @login_required(login_url="user:login") : 로그인 안 됐으면 login_url로 가세욧
@login_required(login_url="user:login")
def post_detail(request, id):
    # ⬇️ Article 모델에 있는 id를 조회해용, 조건에 맞는 객체가 없으면 Http404 페이지 보여줘용
    post = get_object_or_404(Article, id=id)
    context = {"post":post,}
    return render(request, "post/post_detail.html", context) # post_detail.html 양식으로 보여줄게용

 

  • # @login_required(login_url="user:login") : 로그인 안 됐으면 login_url로 가세욧
  • # ⬇️ Article 모델에 있는 id를 조회해용, 조건에 맞는 객체가 없으면 Http404 페이지 보여줘용

2.2.2.3. post_detail.html 추가하기

더보기
<!--게시글 상세 보기-->

{% extends "base.html" %}

{% block content %}
<h2>Post Detail</h2>

<!--제목-->
<h3>{{ post.title }}</h3>

<!--내용-->
<p>{{ post.content }}</p>

<!--작성자 이름-->
<p>{{ post.author.username }}</p>

<!--최초 작성일-->
<p>{{ post.created_at}}</p>

<!--게시글 삭제하기 버튼-->
<a href="{% url 'post:post_delete' post.id %}"><button>Delete Post</button></a>

<!--게시글 수정하기 버튼-->
<a href="{% url 'post:post_update' post.id %}"><button>Edit Post</button></a>

<!--인덱스로 가는 버튼-->
<a href="{% url 'index'%}"><button>Back to Index</button></a>
<hr>

{% endblock content %}

2.2.3. 게시글 작성 기능 (post_create) 

2.2.3.1. urls.py 추가하기

더보기
 path('post-create/', views.post_create, name="post_create"), # 게시글 작성하기

2.2.3.2. views.py 추가하기

더보기
from .forms import ArticleForm

# 게시글 작성
# @login_required(login_url="user:login") : 로그인 안 됐으면 login_url로 가세욧
@login_required(login_url="user:login")
def post_create(request):
    if request.method == "POST":
        # ⬇️ request.POST은 클라이언트가 보낸 POST 요청 데이터, request.FILES은 파일 데이터를 답고 있는 객체
        # form에서 request.FILES : FileFiedl나 ImageField가 있으면 반드시 기입!!
        form = ArticleForm(request.POST, request.FILES) 
        if form.is_valid():
            post = form.save(commit=False)  # commit=False : 자동 저장 잠만 멈춰봐!
            post.author = request.user # 작성자도 기입해줄 거야!! 작성자는 user야
            post.save()
        return redirect("post:post_detail", post.id)
    
    # GET 요청 데이터면, ArticleForm 형태만 보여줄게용
    else:
        form = ArticleForm()
    context = {"form":form}
    return render(request, "post/post_create.html", context) # post_create.html 양식으로 보여줄게용

 

  • # @login_required(login_url="user:login") : 로그인 안 됐으면 login_url로 가세욧
  • # ⬇️ request.POST은 클라이언트가 보낸 POST 요청 데이터, request.FILES은 파일 데이터를 답고 있는 객체
  • # form에서 request.FILES : FileFiedl나 ImageField가 있으면 반드시 기입!!
  • # commit=False : 자동 저장 잠만 멈춰봐!
  • # 작성자도 기입해줄 거야!! 작성자는 user야
  • # GET 요청 데이터면, ArticleForm 형태만 보여줄게용

2.2.3.3. forms.html 추가하기

더보기
from django import forms
from .models import Article

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article # 모델은 Article
        fields = "__all__"  # fields에 있는 모든 것들을 쓸 거야
        exclude = ("author",)   # 작성자는 항목에서 보이지 않도록 제외

 

2.2.3.4. post_create.html 추가하기

더보기
<!--새로운 글 작성-->
{% extends "base.html" %}

{% block content %}
<h1>New Post</h1>

<!--post_create 로직대로 작동할게용-->
<form action="{% url 'post:post_create'%}" method="POST">
    {% csrf_token %}
    {{ form.as_p }}

    <button type="submit">Save</button><br><br>

</form>
<!--post_list로 가버리는 주소-->
<a href='{% url "post:post_list" %}'><button>Go to post list</button></a>

{% endblock content %}

2.2.4. 게시글 수정 기능(post_update)

2.2.4.1. urls.py 추가하기

더보기
path('<int:id>/update/', views.post_update, name="post_update"), # 게시글 수정하기

2.2.4.2. views.py 추가하기

더보기
# 게시글 수정하기
# @login_required(login_url="user:login") : 로그인 안 됐으면 login_url로 가세욧
# @require_http_methods(["GET", "POST"]) : GET과 POST일 때만 작동하도록 코드 보호
@login_required(login_url="user:login")
@require_http_methods(["GET", "POST"])
def post_update(request, id):
    post = get_object_or_404(Article, id=id)    # Article 모델에 있는 id 조건에 맞는 객체 불러올게용, 없으면 404 error
    form = ArticleForm(request.POST, instance=post) # instance : form은 post 내용으로 채울 거예용
    
    if request.user != post.author:
        return redirect('post:post_list')   # user와 author가 다르면 post_list로 돌아가세욧!
    
    if form.is_valid(): # 값이 유효하다면,
        post = form.save()  # 저장하세욧
        return redirect("post:post_detail", post.id)
    
    else:   # 유효하지 않다면,
        form = ArticleForm(instance=post)   # GET일 때도, form이 post로 채워진 걸 보여줘용
    
    context = {
        "post":post,
        "form":form}
    
    return render(request, "post/post_update.html", context)

 

  • # @login_required(login_url="user:login") : 로그인 안 됐으면 login_url로 가세
  • # @require_http_methods(["GET", "POST"]) : GET과 POST일 때만 작동하도록 코드 보
  • # Article 모델에 있는 id 조건에 맞는 객체 불러올게용, 없으면 404 erro
  • # instance : form은 post 내용으로 채울 거예
  • # user와 author가 다르면 post_list로 돌아가세욧
  • # GET일 때도, form이 post로 채워진 걸 보여줘용

2.2.4.3. post_update.html 추가하기

더보기
<!--게시글 수정하기-->

{% extends "base.html" %}

{% block content %}
<h1>Edit Post</h1>

<!--post_update의 로직에 맞춰서 수정하도록 했어용-->
<form action="{% url 'post:post_update' post.id %}" method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Edit Post</button>
</form>

<!--수정하기를 취소하는 버튼이에용-->
<a href="{% url 'post:post_detail' post.id %}"><button>Cancle</button></a> 

{% endblock content %}

2.2.5. 게시글 삭제 기능(post_delete)

2.2.5.1. urls.py 추가하기

더보기
path('<int:id>/delete/', views.post_confirm_delete, name="post_delete"), # 게시글 삭제하기
]

2.2.5.2. views.py 추가하기

더보기
# 게시글 삭제하기
# @login_required(login_url="user:login") : 로그인 안 됐으면 login_url로 가세욧
@login_required(login_url="user:login")
def post_confirm_delete(request, id):
    post = get_object_or_404(Article, id=id)
    
    if request.user != post.author: # 글 작성자가 아니라면,
        return redirect("post:post_list") # post_list로 가세욧
    
    if request.method == "POST":
        post.delete()
        return redirect("post:post_list")
    
    context = {"post":post}
    
    return render(request,'post/post_confirm_delete.html', context)

 

2.2.5.3. post_confirm_delete.html 추가하기

더보기
<!--게시글 삭제할 때 보여지는 화면-->

{% extends "base.html" %}

{% block content %}

<!--진짜로 게시글 삭제할 거야?-->
<h1> Are you serious delete this post?</h1>

<!--삭제할 게시글 제목과 내용-->
<div>
    <p>Title : {{ post.title }}</p>
    <p>Content : {{ post.content }}</p>
</div>
<hr>

<!--post_delete의 로직으로 진행해요-->
<form action="{% url 'post:post_delete' post.id %}" method="POST">
    {% csrf_token %}
    <button type="submit">Yes, Delete</button>
</form>

<!--글 삭제 취소할게용-->
<a href="{% url 'post:post_list'%}"><button>Cancle</button></a>

{% endblock content %}

 

 

🐾Recent posts