[Django] - 나만의 포폴Blog만들기-2

Wooney98·2022년 12월 15일
1

PlayData_BackEnd

목록 보기
18/33

6. 미디어 파일 관리 & 첨부 파일 기능 구현

  • media 절대경로 수정(settings.py)

  • DB에 파일업로드 받을 필드 추가

  • 주의 사항 : == 과 ‘xlsx’ 사이는 1칸 떨어져야 함
    • {% elif post.get_file_ext == 'xlsx' or post.get_file_ext == 'xls' %}
  • getbootstrap icon 사용
  • media 폴더 .gitignore

작성자(author) 필드에 추가

  • ForiegnKey로 Author 필드 추가

1. DB에서 NULL을 허용

2. DB에서 삭제되었을 때 작성자명을 빈 칸으로 둠

📢post 게시물 예외처리
post list 존재 여부에 따른 출력하여 예외처리 하자.

  • blog/templates/blog/post_list.html
<!-- Page content -->
<section class="container">
  			...
    <div class="row">
        <!-- Blog entries-->
        <div class="col-lg-8">
            {% if post_list.exists %}
            {% for p in post_list %}
            <!-- Featured blog post-->
            <div class="card mb-4">
              ...
              ...
              ...
     </div>
</section>
{% else %}
<h3>아직 게시물이 없습니다.</p>
{% endif %}

9. paginations 기능

  • page 사용 설정 추가
    • blog/view.py
class PostList(ListView):
model = Post
# template_name = 'blog/post_list.html'
paginate_by = 2   # pagination 기능 활성화, page 당 2 
ordering = '-pk'
  • {% for p in post_list %} {% endfor %} 문 안에서 순회 순서값 참조
    • forloop.counter : 1부터 순회 카운트
    • forloop.counter0 : 0부터 순회 카운트

https://www.notion.so/4-9-paginations-b842ba4b05184a9687779159a1141e08

10. blog 화면 & 상세페이지 화면 작성자 정보 출력 삭제된 작성자는 None으로 표시

11. 포스트 목록 페이지에 카테고리 기능 추가

  • admin.py
  • models.py

    unique=True : 동일한 name을 갖는 카테고리를 또 만들 수 없다..!
    allow_unicode=True : SlugField에 한글을 지원해준다..!
  • models.py -> post모델에 category 필드 추가

ForeignKey로 연결되어 있던 카테고리가 삭제된 경우 포스트까지 삭제되지 않고 category필드만 null이 되도록 on_delete=models.SET_NULL로 설정

  • views.py -> 카테고리창 기능

    ListView에는 get_context_data메서드를 내장하고있다.
    PostList를 상속받아 context변수에 저장한뒤 원하는 쿼리셋을 만들어 딕셔너리 형태로 context에 담는다. 나는 get_context_data를 2가지 정보를 담기로 정의했다.
    Category.objects.all()Post.objects.filter(category=None)으로
    모든 카테고리를 가져와 categories라는 키에 연결하고, 카테고리가 지정되지 않은 포스트의 개수를 세어 쿼리셋으로 만들어 no_category_post_count에 담는다.

12. 상세페이지에 카테고리 기능 추가

  • views.py에 PostDetail 클래스에도 get_context_data를 정의해준다.
  • 템플릿 수정하면 된다.

13. 카테고리 페이지 구현

카테고리에 따로 모아놓은 텍스트 링크를 클릭 시,

  • 링크 클릭시, url path가 필요하다. -> get_absolute_url()
    • URL에 slug필드를 이용해 고유 URL을 만든다.
class Category(models.Model):
...
...
	def get_absolute_url(self):
    	return f'/blog/category/{self.slug}/'
  • 이제 URL을 정의하자(urls.py)
    category/ 뒤에 문자열이 붙는 URL을 입력하면 views.py에 정의할 category_page()함수의 매개변수인 slug의 인자로 넘겨주도록 했다.
urlpatterns = [
	path('category/<str:slug>/', views.category_page),
    ...
]
  • views.py에서 category_page()를 정의하자..!

    1) FBV 방식, request 이외에 slug까지 설정했다. category_page() 함수의 인자로 받은 slug와 동일한 slug를 갖는 카테고리를 불러오는 쿼리셋을 만들어 category변수에 저장한다. 추가로, 미분류인지 아닌지에 대한 예외처리한 상태이다.
    2) 템플릿
    3) PostList 클래스에서 context로 정의했던 부분을 딕셔너리 형태로 직접 정의해야한다. 'post_list'는 '포스트중 Category.objects.get(slug=slug)로 필터링한 카테고리만 가져와라' 라는 뜻이다. 'categories'는 카테고리 카드를 채워준다. 'no_category_post_count'는 미분류 포스트와 개수를 알려준다. 'category'는 페이지 타이틀 옆에 카테고리 이름을 알려준다.

13-1. Tag모델

  • 구현방법은 카테고리와 비슷하다.

    class Post

ForeignKey가 아니라 ManyToManyField를 사용해 Tag모델을 연결한다.

  • ManyToManyField
    • ManyToManyField로 만든 태그와 포스트는 다대다 관계를 가진다. 즉, 하나의 포스트가 여러개의 태그와 연결될 수 있고, 반대로 하나의 태그가 여러 포스트와 연결될 수 있다. 그래서 태그 하나가 DB에서 삭제된다고 연결된 포스트가 전부 삭제되면 곤란하기에 기본적으로 null=True을 갖는다.
  • admin에 Tag 추가

13-2 포스트 목록 페이지에 태그 기능 추가. + 상세페이지

  • post_list.html
{% for p in post_list %}
	(..생략..)
  {% if p.tags.exists %}
       <i class="bi bi-tags"></i>
          {% for tag in p.tags.iterator %}
             <a href="{{tag.get_absolute_url}}">
               <span class="badge bg-success">{{ tag }}</span></a>
           {% endfor %}
           <br />
    {% endif %}
  • 상세페이지 또한 템플릿 수정하면 됨.

13-3. Tag페이지 구현

  • URL 지정하기 - urls.py
  • views.py

14. 포스트 작성 페이지 만들기

  • CreateView 추가
    • 장고가 제공하는 CreateView를 상속받아 PostCreate라는 클래스를 만든다.
    • model = Post로 Post모델을 사용한다고 정의
    • Post모델에 사용할 필드명을 리스트로 정의
  • URL
urlpatterns=[
    path('create_post/', views.PostCreate.as_view()),
  • 템플릿
    post_form.html생성
{% extends 'base.html' %}
{% load static %}
{% load crispy_forms_tags %}

{% block my_style%}
<link rel="stylesheet" href="{% static 'css/my_style.css' %}">
{% endblock my_style %}

{% block head_title %}::: Create Post - Blog :::{%endblock%}


{% block main_area %}
<section class="container">
    <h1>Create New Post</h1>
<hr />
    <form method="post" enctype="multipart/form-data">{% csrf_token %}

        {{ form | crispy }}

        <button type="submit" class="btn btn-primary float-right">등록</button>
        
    </form>
</section>
{% endblock main_area %}

14-1. 로그인한 방문자만 새 포스트 작성 버튼 나오게 구현

로그아웃 상태에서는 포스트 작성 페이지에 접근할수 없도록 해야한다.

  • views.py의 LoginRequiredMixin
    LoginRequiredMixin클래스를 추가하면 로그인했을 때만 정상적으로 페이지가 보이게 된다.
class PostCreate(LoginRequiredMixin, CreateView):
    model = Post 
    # form 클래스 추가했을경우 제거.
    fields = ['title','hook_text','content','head_image','file_upload','category']
  • 자동으로 author 필드 채우기
    • form_valid() 함수 활용
class PostCreate(LoginRequiredMixin, CreateView):
    model = Post 
    # form 클래스 추가했을경우 제거.
    fields = ['title','hook_text','content','head_image','file_upload','category']
	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
            return super(PostCreate, self).form_valid(form)
        else:
            return redirect('blog/')

1) self.request.user = 방문자
2) 방문자가 로그인한 상태(is_authenticated)인지 아닌지 확인
3) 로그인을 한 상태라면 form에서 생성한 instance의 author 필드에 current_user(현재 접속한 방문자)를 담는다.
4) 만약 방문자가 로그인하지 않은 상태라면 redirect() 함수를 사용하여 '/blog/'로 보낸다.

  • 로그인했을때 작성 버튼 보이기(post_list.html)
profile
👨Education Computer Engineering 🎓Expected Graduation: February 2023 📞Contact info thstjddn77@gmail.com

0개의 댓글