- blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
# loacalhost:8080/
path('', views.post_list, name='post_list'),
# localhost:8080/post/5
path('post/<int:pk>/', views.post_detail, name='post_detail_test'),
# localhost:8080/post/new
path('post/new/', views.post_new, name='post_new'),
# localhost:8080/post/5/edit
path('post/<int:pk>/edit', views.post_edit, name='post_edit'),
# localhost:8080/post/5/delete
path('post/<int:pk>/delete/', views.post_delete, name='post_delete'),
# localhost:8080/post/5/comment
path('post/<int:pk>/comment/', views.add_comment_to_post, name='add_comment_to_post'),
# localhost:8080/comment/5/approve
path('comment/<int:pk>/approve', views.comment_approve, name='comment_approve'),
# localhost:8080/comment/5/remove
path('comment/<int:pk>/remove', views.comment_remove, name='comment_remove'),
]
- blog/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse
from django.utils import timezone
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from .models import Post, Comment
from .forms import PostForm
from .forms import PostModelForm, CommentForm
# Post 목록
def post_list(request):
#name = 'Django'
# return HttpResponse('''
# <h2>Post List</h>
# <p>웰컴 {name}!!!</p>
# <p>{content}<p/>'''.format(name=name, content=request.content_type))
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
@login_required
def post_new(request):
if request.method == "POST":
# Form 데이터를 입력하고 등록요청 시 보여주는 부분
form = PostForm(request.POST)
# Form 데이터가 clean 한 상태
if form.is_valid():
# PostForm 으로 저장하는 법
print(form.cleaned_data)
post = Post.objects.create(author=User.objects.get(username=request.user),
published_date=timezone.now(),
title=form.cleaned_data['title'],
text=form.cleaned_data['text'])
# Post ModelForm 으로 저장하는 법
# title, text 필드의 값이 저장된다.
# post = form.save(commit=False)
# post.author = User.objects.get(username=request.user)
# post.published_date = timezone.now()
# DB에 등록됨
# post.save()
return redirect('post_detail_test', pk=post.pk)
else:
# 등록 Form 보여주는 부분
form = PostForm()
return render(request, 'blog/post_edit.html', {'form': form})
@login_required
def post_edit(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostModelForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = User.objects.get(username=request.user)
post.published_date = timezone.now()
post.save()
return redirect('post_detail_test', pk=post.pk)
else:
form = PostModelForm(instance=post)
return render(request, 'blog/post_edit.html', {'form': form})
@login_required
def post_delete(request, pk):
post = get_object_or_404(Post, pk=pk)
post.delete()
return redirect('post_list')
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail_test', pk=post.pk)
else:
form = CommentForm()
return render(request, 'blog/add_comment_to_post.html', {'form': form})
@login_required
def comment_approve(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.approve()
return redirect('post_detail_test', pk=comment.post.pk)
@login_required
def comment_remove(request, pk):
comment = get_object_or_404(Comment, pk=pk)
post_pk = comment.post.pk
comment.delete()
return redirect('post_detail_test', pk=post_pk)
- blog/templates/blog/base.html
<!DOCTYPE html>
{% load static %}
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Blog List</title>
{% load static %}
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap-theme.min.css" integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">
<!-- google lobster font-->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext"
type="text/css">
<!-- google Chilanka fonf-->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Chilanka&subset=latin,latin-ext"
type="text/css">
<!-- 개발자 정의 CSS-->
<link rel="stylesheet" href="{% static 'css/blog.css' %}">
<!-- favicon 적용하기 -->
<link rel="shortcut icon" href="{%static 'favicon.ico'%}">
</head>
<body>
<div class="page-header">
{% if user.is_authenticated %}
<a href="{% url 'post_new' %}" class="top-menu">
<span class="glyphicon glyphicon-plus"></span>
</a>
<p class="top-menu">Hello {{user.username}}
<small>(<a href="{% url 'logout' %}?next={{request.path}}">Log out</a> )</small></p>
{% else %}
<a href="{% url 'login' %}" class="top-menu">
<span class="glyphicon glyphicon-lock"></span>
</a>
{% endif %}
<h1><a href="/">Django Blog</a></h1>
</div>
<div class="content container">
<div class="row">
<div class="col-md-8">
{% block content %}
{% endblock %}
</div>
</div>
</div>
{% comment "Optional note" %}
Server comment
{% endcomment %}
<!-- html Client Comment -->
</body>
</html>
- blog/templates/blog/add_comment_to_post.html
{% extends 'blog/base.html' %}
{% block content %}
<table>
<h1>New Comment</h1>
<form method="POST" class="post-form">
{% csrf_token %}
<table class="table table-bordered table-hover">
{{form.as_table}}
</table>
<button type="submit" class="save btn btn-default">Send</button>
</form>
</table>
{% endblock%}
- blog/templates/blog/post_list.html
{% extends 'blog/base.html' %}
{% block content%}
{% for post in posts %}
<div class="post">
<div class="date">
<p>published : {{post.published_date}}</p>
</div>
<h1><a href="{% url 'post_detail_test' pk=post.pk %}">{{post.title}}</a></h1>
<a href="{% url 'post_detail_test' pk=post.pk %}">Comments: {{post.approved_comments.count}}</a>
</div>
{% empty %}
<div>요청하신 Post가 존재하지 않습니다. </div>
{% endfor %}
{% endblock %}
- blog/templates/blog/post_detail.html
{% extends 'blog/base.html' %}
{% block content%}
<script>
function post_remove(){
//{% url 'post_delete' pk=post.pk %}
var result = confirm('삭제하시겠습니까?')
if(result){
var remove_url = "{% url 'post_delete' pk=post.pk %}"
document.location.href = remove_url
}
}
</script>
<div class="post">
{% if post.published_date%}
<div class="date">
{{post.published_date}}
</div>
{% endif %}
{% if user.is_authenticated %}
<a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}">
<span class="glyphicon glyphicon-pencil"></span>
</a>
<a class="btn btn-default" href="#" onclick="post_remove()">
<span class="glyphicon glyphicon-remove"></span>
</a>
{% endif %}
<h1>{{post.title}}</h1>
<p>{{post.text|linebreaksbr}}</p>
</div>
<hr>
<a class="btn btn-default" href="{% url 'add_comment_to_post' pk=post.pk %}">Add comment</a>
{% for comment in post.comments.all %}
{% if user.is_authenticated or comment.approved_comment %}
<div class="comment">
<div class="date">
{{comment.created_date}}
{% if not comment.approved_comment %}
<a class="btn btn-default" href="{% url 'comment_remove' pk=comment.pk %}">
<span class="glyphicon glyphicon-remove"></span>
</a>
<a class="btn btn-default" href="{% url 'comment_approve' pk=comment.pk %}">
<span class="glyphicon glyphicon-ok"></span>
</a>
{% endif %}
</div>
<strong>{{comment.author}}</strong>
<p>{{comment.text|linebreaks}}</p>
</div>
{% endif %}
{% empty %}
<p>No comment here yet :(</p>
{% endfor %}
{% endblock %}
- blog/templates/registration/login.html
{% extends "blog/base.html" %}
{% block content %}
{% if form.errors %}
<p>이름과 비밀번호가 일치하지 않습니다. 다시 시도해주세요.</p>
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table class="table table-bordered table-hover">
<tr>
<td>{{form.username.label_tag}}</td><td>{{form.username}}</td>
<td>{{form.password.label_tag}}</td><td>{{form.password}}</td>
</tr>
</table>
<input type="submit" value="login" class="btn btn-primary btn-lg"/>
<input type="hidden" name="next" value="{{next}}"/>
</form>
{% endblock %}
- mydjango/settings.py
"""
Django settings for mydjango project.
Generated by 'django-admin startproject' using Django 3.0.9.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""
import os
import pymysql
pymysql.version_info = (1, 3, 13, "final", 0)
pymysql.install_as_MySQLdb()
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'i2t1nrwlwsdu&gl1-z-^nlc75%rp(gndy9-etx=&wsg%wb6^&5'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
'Board',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'mydjango.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'mydjango.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db', # DB명
'USER': 'python', # 데이터베이스 계정
'PASSWORD': 'python', # 계정 비밀번호
'HOST': 'localhost', # 데이테베이스 IP
'PORT': '3306', # 데이터베이스 port
}
}
# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/
LANGUAGE_CODE = 'ko'
TIME_ZONE = 'Asia/Seoul'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, STATIC_URL)
LOGIN_REDIRECT_URL = '/'
- blog/models.py
from django.db import models
from django.utils import timezone
from django import forms
def min_length_3_validator(value):
if len(value) < 3:
raise forms.ValidationError('제목은 3글자 이상 입력해주세요')
# Create your models here.
class Post(models.Model):
# 작성자
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
# 제목
title = models.CharField(max_length=200, validators=[min_length_3_validator])
# 내용
text = models.TextField()
# 작성일자
created_date = models.DateTimeField(default=timezone.now)
# 게시일자
published_date = models.DateTimeField(blank=True, null=True)
# 필드 추가 - 삭제할 예정
#test = models.TextField()
# 게시 일자에 현재 날짜를 대입해주는 함수
def publish(self):
self.published_date = timezone.now()
self.save()
# 객체 주소 대신 글제목을 반한해주는 toString()함수
def __str__(self):
return self.title
def approved_comments(self):
return self.comments.filter(approved_comment=True)
class Comment(models.Model):
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
- blog/forms.py
from django import forms
from .models import Post, Comment
# validator 함수 정의
# title 입력필드의 길이 체크 < 3
def min_length_3_validator(value):
if len(value) < 3:
raise forms.ValidationError('title은 3글자 이상 입력해주세요')
# PostFrom 클래스 선언
class PostForm(forms.Form):
# title = forms.CharField()
title = forms.CharField(validators=[min_length_3_validator])
text = forms.CharField(widget=forms.Textarea)
# PostModelFrom 클래스 선언
class PostModelForm(forms.ModelForm):
# title = forms.CharField()
# title = forms.CharField(validators=[min_length_3_validator])
# text = forms.CharField(widget=forms.Textarea)
class Meta:
model = Post
fields = ('title', 'text',)
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('author', 'text')
- blog/admin.py
from django.contrib import admin
from .models import Post, Comment
class PostAdmin(admin.ModelAdmin):
list_display = ['id', 'title', 'count_text']
list_display_links = ['title']
def count_text(self, obj):
return '{}글자'.format(len(obj.text))
count_text.short_description = 'text 글자수'
# Register your models here.
admin.site.register(Post, PostAdmin)
admin.site.register(Comment)
- blog/static/css/blog.css
.page-header{
background-color: #ed7777;
margin-top: 0;
padding: 20px 20px 20px 40px;
}
.page-header h1, .page-header h1 a, .page-header h1 a:visited, .page-header h1 a:active{
color: #53228f;
font-size: 36pt;
text-decoration: none;
}
h1, h2, h3, h4, .top-menu{
font-family:'Chilanka';
font-size: 16pt;
}
.content{
margin-left:40px;
}
.date{color: #828282;}
.save{float:right;}
.post-from textarea, .post-form input{width:100%;}
.top-menu, .top-menu:hover, .top-menu:visited{
color: #ffffff;
float:right;
font-size:26pt;
margin-right:20px;
}
.post{margin-bottom:70px;}
.post h1 a, .post h1 a:visited{color:#000000;}
.comment{
margin: 20px 0px 20px 20px;
}
- 결과화면
1) 댓글이 등록되어있지 않으면 No comment here yet :( 라고 출력됨
2) 댓글 입력
3) 입력 후 저장 누른 화면
4) 저장을 했어도 approve버튼을 클릭하지 않으면 Comment갯수가 0개라고 나옴
5) 다시 돌아가서 approve 버튼 클릭
6) 다음과 같이 삭제 및 approve버튼 사라짐
7) 이제는 Comments갯수가 1개로 출력
'Python > Django' 카테고리의 다른 글
django 와 mongodb연동 (0) | 2020.08.17 |
---|---|
페이지네이션 (0) | 2020.08.11 |
Django 템플릿 상속 / 게시판 만들기 (0) | 2020.08.06 |
Django (Migrate / URLConf / View / Template / QuerySet / Bootstrap) (0) | 2020.08.05 |
Django설치 및 설정 & 간단한 게시판 만들기 (0) | 2020.08.04 |