[Django/사용자 게시판 만들기]

SooYeon Yeon·2022년 6월 20일
0

Django

목록 보기
6/20

사용자 게시판 만들기

구현 목록

board

  • create : 로그인 한 사용자만 가능, 로그인한 사용자가 작성자가 됨
  • read (해당 내용 읽기)
  • list (전체 읽기)
  • delete : 작성자만이 삭제 가능
  • update : 작성자만이 수정 가능

user

  • 회원가입
  • 로그인
  • 로그아웃

reply

  • create : 로그인 한 사용자만 가능, 로그인한 사용자가 작성자가 됨
  • read (해당 내용 읽기)
  • list (전체 읽기)
  • delete : 작성자만이 삭제 가능
  • update : 작성자만이 수정 가능

작업 진행

  1. python .\manage.py startapp [앱이름]
  2. settings에 앱 이름 추가
  3. model 클래스 만들기
  4. python .\manage.py makemigrations [앱이름]
  5. python .\manage.py migrate
  6. views.py 등 작업 수행

유저는 모델을 만들지 않고 장고에서 기본적으로 제공하는 모델을 사용할 예정

user-board 1:n 관계

user-reply 1:n 관계

writer 설정하기

  1. 모델에 외래키로 추가
  2. views에서 xxx.writer = request.user
  3. Form에 exclude 추가
  4. makemigrations [n에 해당하는거]
  5. migrate
  6. urls 수정

login 여부

데코레이터(자바에서는 어노테이션) @login_required() 을 추가해 login이 되어있어야만 가능하게 함

@login_required(login_url='/user/login')

로그인 안해줬을 때는 로그인 창 띄워줌, 여기서 로그인 하면 원래 가려고 했던 페이지로 가짐

코드

urls.py

from django.contrib import admin
from django.urls import path

import board.views
import product.views
import reply.views
import user.views

urlpatterns = [
    path('admin/', admin.site.urls),

    path('board/create',board.views.create),
    path('board/listGet',board.views.listGet),
    path('board/readGet/<int:bid>',board.views.readGet),
    path('board/deleteGet/<int:bid>',board.views.deleteGet),
    path('board/update/<int:bid>',board.views.update),

    path('reply/create',reply.views.create),
    path('reply/list',reply.views.list),
    path('reply/read/<int:rid>',reply.views.read),
    path('reply/delete/<int:rid>',reply.views.delete),
    path('reply/update/<int:rid>',reply.views.update),

    path('user/signup', user.views.singup),
    path('user/login', user.views.login),
    path('user/logout', user.views.logout),

]

board

forms.py

from django import forms

from board.models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post # model은 Post 양식으로 쓰겠다.
        fields = ('title', 'contents') # 어떤 필드를 입력 받을 지
        exclude = ('writer', ) # 폼에서 writer 입력받지 않게 함

models.py

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

# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=40)
    contents = models.TextField()
    create_date = models.DateTimeField(auto_now_add=True)

    # writer은 다른 모델을 참조하겠다.(User) 외래키 추가
    writer = models.ForeignKey(User, on_delete=models.CASCADE) # on_delete : User가 delete 될 때 게시글을 어떻게 설정한 것인지에 대해 설정 1. 게시글 같이 지우기(CASCADE) 2. 없는 값으로 해서 게시글은 남겨두기

    def __str__(self):
        return 'id : {}, title : {}'.format(self.id, self.title, self.contents)

views.py

from django.contrib.auth.decorators import login_required
from django.db.models import Q
from django.shortcuts import render, redirect

# Create your views here.
from board.forms import PostForm
from board.models import Post

@login_required(login_url='/user/login')
def create(request):
    if request.method == "GET": # 작성하거나 수정할 페이지 띄워줌
        # postForm을 이용해 정보를 받아옴
        postForm = PostForm()
        context = {'postForm' : postForm}
        return render(request, 'board/create.html',context)
    elif request.method == "POST": # 실제 그 내용이 DB에 저장되도록
        # postForm을 받아와 유효성 확인이 되면, save 해줌
        postForm = PostForm(request.POST)
        if postForm.is_valid():
            post = postForm.save(commit=False)
            post.writer = request.user  # 현재 로그인한 사용자를 writer로 고정시켜줘야함
            post.save()
        return redirect('/board/readGet/'+str(post.id)) # 자기가 쓴 게시물 조회로 가도록 함

def listGet(request):
    posts = Post.objects.all().order_by('-id') # id 순으로 정렬하는데 - 니까 오름차순으로 정렬
    context = {'posts' : posts}
    return render(request, 'board/list.html',context)

def readGet(request, bid):
    # post = Post.objects.filter(id=bid)
    post = Post.objects.get(Q(id=bid)) # Q (장고에 있는 모델) 이용해서 하나만 조회 가능 (filter은 for문 해야하는데 이 경우 하나만 가능)
    context = {
        'post' : post
    }

    return render(request, 'board/read.html',context)

@login_required(login_url='/user/login')
def deleteGet(request,bid):
    post = Post.objects.get(id=bid) # Q 안쓰고도 가능, Q는 쿼리 들어갈 때 여러 기능
    # writer와 현재 user가 같을 때만 삭제 시켜줘야 함
    if request.user != post.writer:
        return redirect('/board/listGet')
    post.delete()
    return redirect('/board/listGet') # board의 list url로 redirect 되게 함

@login_required(login_url='/user/login')
def update(request,bid):
    # 해당 게시글이 한번 조회가 되어야 함
    post = Post.objects.get(id=bid)
    if request.method == "GET" : # 작성하거나 수정할 페이지 띄워줌
        postForm = PostForm(instance=post) # 조회 된 postForm을 유지해서 가져와야 함
        context = {'postForm' : postForm}

        return render(request,'board/create.html',context) # 수정할 페이지를 띄워줌

    elif request.method == "POST" : # 실제 그 내용이 DB에 저장되도록
        postForm = PostForm(request.POST, instance=post) # 위에서 받아온 게시물의 내용을 Form으로 받아옴
        if postForm.is_valid():
            post = postForm.save(commit=False)
            post.save()

        return redirect('/board/readGet/'+str(post.id))# 수정 후 조회하는 곳으로 이동

create.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post">
    {% csrf_token %}
    {{ postForm }}
    <button>작성</button>
</form>

</body>
</html>

list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!-- authenticated가 되어있으면(True) 글씨를 뜨게 함-->
{% if request.user.is_authenticated%}
로그인 한 사용자 : {{ request.user }} <br/>
{% endif %}

{% for post in posts %}
    {{ post.id }}
<!-- postid에 해당하는 contents를 클릭하면 해당 id의 readGet으로 이동 -->
    <a href="readGet/{{ post.id }}"> {{ post.contents }} </a>
    {{ post.writer }}
<br/>
{% endfor %}
<a href="../board/create">게시글 작성</a>
</body>
</html>

read.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% if post %}
    {{ post.id }}
    {{ post.title }} <br/>
    <a href="/board/listGet">목록</a>
    <!--작성자와 로그인 한 유저가 일치해야만 수정, 삭제 버튼이 보이도록 함 -->
    {% if post.writer == request.user %}
    <a href="/board/update/{{post.id}}">수정</a>
    <a href="/board/deleteGet/{{post.id}}">삭제</a>
    {% endif %}
{% endif %}

</body>
</html>

user

views.py

from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.shortcuts import render, redirect
from django.contrib.auth import login as auth_login, logout as auth_logout # login함수이름과 겹쳐서 auth_login으로 해줌

# 회원가입
def singup(request):
    if request.method == "GET":
        signupForm = UserCreationForm() # 장고에서 제공하는 유저 Form
        return render(request,'user/signup.html', {'signupForm':signupForm})
    elif request.method == "POST":
        signupForm = UserCreationForm(request.POST)
        if signupForm.is_valid():
            user = signupForm.save(commit=False)
            user.save()

        return redirect('/board/listGet') # 회원가입 하면 게시글 목록으로 가도록 이동시켜줌

# 로그인 입력 양식이 주어져야함
def login(request):
    if request.method == "GET":
        loginForm = AuthenticationForm() # 로그인 시 사용하는 Form
        return render(request,'user/login.html', {'loginForm' : loginForm})
    elif request.method == "POST":
        loginForm = AuthenticationForm(request, request.POST) # request와 request.POST를 둘 다 넣어주어야 함
        if loginForm.is_valid():
            auth_login(request, loginForm.get_user()) # request, 유저정보를 뽑아 넣어줌 id, pw를 직접 뽑아내서 아이디 비번 맞는지 할 필요 없이 이렇게 하면됨
            return redirect('/board/listGet')

def logout(request):
    # 세션 정보를 지우는 것
    auth_logout(request)
    return redirect('/board/listGet')

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post">
    {% csrf_token %}
    {{ loginForm }}
  <button>로그인</button>
</form>
</body>
</html>

signup.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post">
  {% csrf_token %}
  {{ signupForm }}
  <button>회원가입</button>
</form>
</body>
</html>

reply

forms.py

from django import forms

from reply.models import Reply

class ReplyForm(forms.ModelForm):
    class Meta:
        model = Reply # model은 Post 양식으로 쓰겠다.
        fields = ('contents',) # 어떤 필드를 입력 받을 지
        exclude = ('writer',)

models.py

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

# Create your models here.
class Reply(models.Model):
    contents = models.TextField()
    create_date = models.DateTimeField(auto_now_add=True)
    writer = models.ForeignKey(User, on_delete=models.CASCADE)

views.py

from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect

# Create your views here.
from reply.forms import ReplyForm
from reply.models import Reply

@login_required(login_url='/user/login')
def create(request):
    if request.method == "GET":
        replyForm = ReplyForm()
        context = {'replyForm':replyForm}
        return render(request, 'reply/create.html', context)
    elif request.method == "POST":
        replyForm = ReplyForm(request.POST)
        if replyForm.is_valid():
            reply = replyForm.save(commit=False) # 저장 전 확인
            reply.writer = request.user
            reply.save()
        return redirect('/reply/read/'+str(reply.id)) # 자신이 쓴 댓글로 가도록함

def read(request,rid):
    reply = Reply.objects.get(id=rid)
    context = {
        'reply' : reply
    }
    return render(request,'reply/read.html',context)

def list(request):
    replys = Reply.objects.all().order_by('-id')
    context = {
        'replys' : replys
    }
    return render(request, 'reply/list.html',context)

def delete(request,rid):
    reply = Reply.objects.get(id=rid)
    reply.delete()

    return redirect('/reply/list')

def update(request,rid):
    reply = Reply.objects.get(id=rid)
    if request.method == "GET":
        replyForm = ReplyForm(instance=reply)
        context = {'replyForm':replyForm}
        return render(request, 'reply/create.html', context)
    elif request.method == "POST":
        replyForm = ReplyForm(request.POST, instance=reply)
        if replyForm.is_valid():
            reply = replyForm.save(commit=False) # 저장 전 확인
            reply.save()
        return redirect('/reply/read/'+str(reply.id)) # 자신이 쓴 댓글로 가도록함
    return render()

create.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post">
  {% csrf_token %}
  {{ replyForm }}
    <button>전송</button>
</form>

</body>
</html>

list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% for reply in replys %}
    {{ reply.id }}
    {{ reply.writer }}
<!-- postid에 해당하는 contents를 클릭하면 해당 id의 readGet으로 이동 -->
    <a href="read/{{ reply.id }}"> {{ reply.contents }} </a>
    {{post.create_date}} <br/>
{% endfor %}
</body>
</html>

read.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% if reply %}
    {{ reply.id }}
    {{ reply.contents }} <br/>
<a href="/reply/update/{{reply.id}}">수정</a>
<a href="/reply/delete/{{reply.id}}">삭제</a>
{% endif %}
</body>
</html>

0개의 댓글