도움: https://velog.io/@sawol/Django-%EC%9A%A9%EC%96%B4-%EC%A0%95%EB%A6%AC
추가해줌.
path('tag/<str:slug>/',views.tag_page),
path('<int:pk>/new_comment/',views.new_comment),
추가해줌.
def tag_page(request, slug):
tag = Tag.objects.get(slug=slug)
post_list = tag.post_set.all()
return render(
request,
'blog/post_list.html',
{
'post_list': post_list,
'tag': tag,
'categories': Category.objects.all(),
'no_category_post_count': Post.objects.filter(category=None).count(),
}
)
def new_comment(request, pk):
if request.user.is_authenticated:
post = get_object_or_404(Post, pk=pk)
if request.method == 'POST':
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.post = post
comment.author = request.user
comment.save()
return redirect(comment.get_absolute_url())
else:
return redirect(post.get_absolute_url())
else:
raise PermissionDenied
from .models import Comment
from django import forms
class Commentform(forms.ModelForm):
class Meta:
model = Comment
fields = ("content",)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block head_title %}Blog{% endblock %}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css">
<script src="https://kit.fontawesome.com/164c3bc1c6.js" crossorigin="anonymous"></script>
{% comment %} https://fontawesome.com/ 에서 이메일로 받은 링크 클릭하여 회원 가입 후 kit code를 script안에 입력{% endcomment %}
</head>
<body>
{% include 'blog/navbar.html'%}
<div class="container my-3">
<div class="row">
<div class="col-md-8 col-lg-9" id="main-area">
{% block main_area %}
{% endblock %}
</div>
<div class="col-md-4 col-lg-3">
<!-- Search Widget --> ### -> 이부분 추가 됨!!!
<div class="card my-4">
<h5 class="card-header">Search</h5>
<div class="card-body">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search for...">
<span class="input-group-btn">
<button class="btn btn-secondary" type="button">Go!</button>
</span>
</div>
</div>
</div>
<!-- Categories Widget -->
<div class="card my-4" id="categories-card">
<h5 class="card-header">Categories</h5>
<div class="card-body">
<div class="row">
<ul>
{% for category in categories %}
<li>
<a href="{{ category.get_absolute_url }}">{{ category }} ({{ category.post_set.count }})</a>
</li>
{% endfor %}
<li>
<a href="/blog/category/no_category/">미분류 ({{ no_category_post_count }})</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
{% block main_area %} {%endblock%}
<div clas="fixed-bottom">
{% include 'blog/footer.html'%}
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js"></script>
</body>
</html>
{% load socialaccount %}
<!-- Modal -->
<div class="modal fade" id="loginModal" tabindex="-1" role="dialog" aria-labelledby="logInModalLabel"
aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="loginModalLabel"> <i class="fas fa-sign-in-alt"></i>  Log In</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-6">
<a role="button" class="btn btn-outline-dark btn-block btn-sm " href="{% provider_login_url 'google' %}"><i class="fab fa-google"></i>   Log in with Google</a>
<a role="button" class="btn btn-outline-dark btn-block btn-sm" href="/accounts/login/"><i class="far fa-envelope"></i>   Log in with Username</a>
</div>
<div class="col-md-6">
<a role="button" class="btn btn-outline-dark btn-block btn-sm" href="/accounts/signup/"><i class="far fa-envelope"></i>   Sign Up with E-mail</a>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div
{% extends 'blog/base.html' %}
{% block main_area %}
{% if user.is_authenticated%}
{% if user.is_superuser or user.is_staff %}
<a class="btn btn-info btn-sm float-right" href="/blog/create_post/" role="button"><i class="fas fa-pen"></i> New Post</a>
{% endif %}
{% endif %}
<h1>Blog
{% if search_info %}<small class="text-muted">{{ search_info }}</small>{% endif %}
{% if category %}<span class="badge badge-secondary">{{ category }}</span>{% endif %}
{% if tag %}<span class="badge badge-light"><i class="fas fa-tags"></i>{{ tag }} ({{ tag.post_set.count }})</span>{% endif %}
</h1>
{% if post_list.exists %}
{% for p in post_list %}
<!-- Blog Post -->
<div class="card mb-4" id="post-{{p.pk}}">
{% if p.head_image %}
<img class="card-img-top" src="{{ p.head_image.url }}" alt="{{ p }} head image">
{% else %}
<img class="card-img-top" src="https://picsum.photos/seed/%7B%7B p.id }}/800/200" alt="random_image">
{% endif %}
<div class="card-body">
{% if p.category %}
<span class="badge badge-secondary float-right">{{ p.category }}</span>
{% else %}
<span class="badge badge-secondary float-right">미분류</span>
{% endif %}
<h2 class="card-title">{{ p.title}}</h2>
{% if p.hook_text %}
<h5 class="text-muted">{{ p.hook_text }}</h5>
{% endif %}
<!-- 마트다운 적용 -->
<p class="card-text">{{ p.get_content_markdown | truncatewords_html:45 | safe }}</p>
{% if p.tags.exists %}
<i class="fas fa-tags"></i>
{% for tag in p.tags.iterator %}
<a href="{{ tag.get_absolute_url }}"><span class="badge badge-pill badge-light">{{ tag }}</span></a>
{% endfor %}
<br/>
<br/>
{% endif %}
<a href="{{ p.get_absolute_url }}" class="btn btn-primary">Read More →</a>
</div>
<div class="card-footer text-muted">
Posted on {{ p.created_at}} by
<a href="#">{{p.author | upper}}</a>
</div>
</div>
{% endfor %}
{% else %}
<h3>아직 게시물이 없습니다.</h3>
{% endif %}
{% if is_paginated %}
<!-- Pagination -->
<ul class="pagination justify-content-center mb-4">
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">← Older</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#">← Older</a>
</li>
{% endif %}
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Newer →</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#">Newer →</a>
</li>
{% endif %}
</ul>
{% endif %}
{% endblock %}
<!DOCTYPE html>
<html>
{% load static %}
<head>
<title>{% block head_title %}Blog{% endblock %}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css%22%3E
<script src="https://kit.fontawesome.com/193173e32d.js%22 crossorigin="anonymous"></script>
</head>
<body>
{% include 'blog/navbar.html' %}
<div class="container my-3">
<div class="row">
<div class="col-12" id="main-area">
{% block main_area %}
{% endblock %}
</div>
</div>
</div>
{% include 'blog/footer.html' %}
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js%22%3E%3C/script%3E
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js%22%3E%3C/script%3E
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js%22%3E%3C/script%3E
</body>
</html>
{% extends 'blog/base_full_width.html' %}
{% load crispy_forms_tags %}
{% block head_title %}Create Post - Blog{% endblock %}
{% block main_area %}
<h1>Create New Post</h1>
<hr/>
<form method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form | crispy }}
<!-- 적용하고 싶은 폼에 아래와 같이 '| crispy' 붙이기 -->
<div id="div_id_tags_str">
<label for="id_tags_str">Tags:</label>
<input type="text" name="tags_str" id="id_tags_str" class="textinput textInput form-control">
</div>
<br/>
<button type="submit" class="btn btn-primary float-right">Submit</button>
</form>
{{form.media}}
{% endblock %}
{% extends 'blog/base_full_width.html' %}
{% load crispy_forms_tags %}
{% block head_title %}Edit Comment - Blog{% endblock %}
{% block main_area %}
<h1>Edit Comment</h1>
<hr/>
<form method="post" id="comment-form">{% csrf_token %}
{{ form | crispy }}
<br/>
<button type="submit" class="btn btn-primary float-right">Submit</button>
</form>
{% endblock %}
{% extends 'blog/base_full_width.html' %}
{% load crispy_forms_tags %}
{% block head_title %}Edit Post - Blog{% endblock %}
{% block main_area %}
<h1>Edit Post</h1>
<hr/>
<form method="post" enctype="multipart/form-data">{% csrf_token %}
{{ form | crispy }}
<!-- 적용하고 싶은 폼에 아래와 같이 '| crispy' 붙이기 -->
<div id="div_id_tags_str">
<label for="id_tags_str">Tags:</label>
<input type="text" name="tags_str" id="id_tags_str" class="textinput textInput form-control">
</div>
<br/>
<button type="submit" class="btn btn-primary float-right">Submit</button>
</form>
{{form.media}}
{% endblock %}
path('delete_comment/<int:pk>/', views.delete_comment),
path('update_comment/<int:pk>/', views.CommentUpdate.as_view()),
path('update_post/<int:pk>/', views.PostUpdate.as_view()),
path('create_post/', views.PostCreate.as_view()),
from django.shortcuts import render, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.utils.text import slugify
from django.shortcuts import get_object_or_404
from .models import Post, Category, Tag , Comment
from. forms import Commentform
from django.core.exceptions import PermissionDenied
from django.db.models import Q
class PostList(ListView):
model = Post
ordering = '-pk'
def get_context_data(self, **kwargs):
context = super(PostList, self).get_context_data()
context['categories'] = Category.objects.all()
context['no_category_post_count'] = Post.objects.filter(category=None).count()
return context
class PostDetail(DetailView):
model = Post
def get_context_data(self, **kwargs):
context = super(PostDetail, self).get_context_data()
context['categories'] = Category.objects.all()
context['no_category_post_count'] = Post.objects.filter(category=None).count()
return context
class PostCreate(LoginRequiredMixin, UserPassesTestMixin, CreateView):
model = Post
fields = ['title', 'hook_text', 'content', 'head_image', 'file_upload', 'category']
def test_func(self):
return self.request.user.is_superuser or self.request.user.is_staff
def form_valid(self, form):
current_user = self.request.user
if current_user.is_authenticated and (current_user.is_staff or current_user.is_superuser):
form.instance.author = current_user
response = super(PostCreate, self).form_valid(form)
tags_str = self.request.POST.get('tags_str')
if tags_str:
tags_str = tags_str.strip()
tags_str = tags_str.replace(',', ';')
tags_list = tags_str.split(';')
for t in tags_list:
t = t.strip()
tag, is_tag_created = Tag.objects.get_or_create(name=t)
if is_tag_created:
tag.slug = slugify(t, allow_unicode=True)
tag.save()
self.object.tags.add(tag)
return response
else:
return redirect('/blog/')
class PostUpdate(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'hook_text', 'content', 'head_image', 'file_upload', 'category', 'tags']
template_name = 'blog/post_update_form.html'
def get_context_data(self, **kwargs):
context = super(PostUpdate, self).get_context_data()
if self.object.tags.exists():
tags_str_list = list()
for t in self.object.tags.all():
tags_str_list.append(t.name)
context['tags_str_default'] = '; '.join(tags_str_list)
return context
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated and request.user == self.get_object().author:
return super(PostUpdate, self).dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
def form_valid(self, form):
response = super(PostUpdate, self).form_valid(form)
self.object.tags.clear()
tags_str = self.request.POST.get('tags_str')
if tags_str:
tags_str = tags_str.strip()
tags_str = tags_str.replace(',', ';')
tags_list = tags_str.split(';')
for t in tags_list:
t = t.strip()
tag, is_tag_created = Tag.objects.get_or_create(name=t)
if is_tag_created:
tag.slug = slugify(t, allow_unicode=True)
tag.save()
self.object.tags.add(tag)
return response
def category_page(request, slug): # slug는 일반적으로 이미 얻은 데이터를 사용하여 유효한 url을 생성하는 방법
if slug == 'no category':
category = '미분류'
post_list = Post.objects.filter(category=None)
else:
category = Category.objects.get(slug=slug)
post_list = Post.objects.filter(category=category)
return render(
request,
'blog/post_list.html',
{
'post_list': post_list,
'categories': Category.objects.all(),
'no_category_post_count': Post.objects.filter(category=None).count(),
'category':category,
}
)
def tag_page(request, slug):
tag = Tag.objects.get(slug=slug)
post_list = tag.post_set.all()
return render(
request,
'blog/post_list.html',
{
'post_list': post_list,
'tag': tag,
'categories': Category.objects.all(),
'no_category_post_count': Post.objects.filter(category=None).count(),
}
)
def new_comment(request, pk):
if request.user.is_authenticated:
post = get_object_or_404(Post, pk=pk)
if request.method == 'POST':
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
comment = comment_form.save(commit=False)
comment.post = post
comment.author = request.user
comment.save()
return redirect(comment.get_absolute_url())
else:
return redirect(post.get_absolute_url())
else:
raise PermissionDenied
class CommentUpdate(LoginRequiredMixin, UpdateView):
model = Comment
form_class = CommentForm
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated and request.user == self.get_object().author:
return super(CommentUpdate, self).dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
def delete_comment(request, pk):
comment = get_object_or_404(Comment, pk=pk)
post = comment.post
if request.user.is_authenticated and request.user == comment.author:
comment.delete()
return redirect(post.get_absolute_url())
else:
raise PermissionDenied
class PostSearch(PostList):
paginate_by = None
def get_queryset(self):
q = self.kwargs['q']
post_list = Post.objects.filter(
Q(title__contains=q) | Q(tags__name__contains=q)
).distinct()
return post_list
def get_context_data(self, **kwargs):
context = super(PostSearch, self).get_context_data()
q = self.kwargs['q']
context['search_info'] = f'Search: {q} ({self.get_queryset().count()})'
return context
내일 예습
로그인