그 전까지는 함수 기반 뷰를 이용해서 views.py를 만들었지만, 이제는 클래스 기반 뷰를 통해서 좀 더 쉽게 만들어보자.
generic 클래스에 대한
실습
이제는 각 프로젝트마다 venv를 만들지않고 하나의 가상환경을 계속해서 쓰자.
pip freeze > requirements.txt 를 이용해서 버전관리를 할 수 있다.
설치할때는 pip install -r requirements.txt 사용
그리고 .gitignore파일을 만들고 venv를 입력해서 가상환경은 무시하도록 한다.
startproject를 하고, startapp으로 blog를 만들어서 클래스 기반 뷰를 사용해보자.
tutorialdjango / urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')),
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings.py 추가
맨 마지막 줄에 MEDIA_ROOT와 MEDIA_URL 추가
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = '/media/'
blog / urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.postlist, name='postlist'), # 리스트
path('<int:pk>/', views.postdetail, name='postdetail'), # 디테일
path('write/', views.write, name='write'), # 생성
path('edit/<int:pk>/', views.edit, name='edit'), # 업데이트
path('delete/<int:pk>/', views.delete, name='delete'), # 삭제
]
blog / models.py
저장 후 python manage.py makemigrations, migrate 꼭 하기
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
head_image = models.ImageField(
upload_to='blog/images/%Y/%m/%d/', blank=True)
file_upload = models.FileField(
upload_to='blog/files/%Y/%m/%d/', blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateField(auto_now=True)
def __str__(self):
return self.title
blog / views.py
Django에 내장하고있는 generic 클래스들을 이용해서 CRUD를 구현한다.
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from .models import Post
from django.urls import reverse_lazy
# 클래스 상속받아서 생성
class PostList(ListView):
model = Post # models.py의 Post를 모델로 하겠다.
ordering = '-pk' # 게시글 순서를 최신글이 위로오게 변경
# template_name = 'blog/변경.html' # template은 이런식으로 변경
class PostDetail(DetailView):
model = Post
class PostCreate(CreateView):
model = Post
fields = '__all__' # 입력할 필드를 설정 ex) ['title', 'content']
success_url = reverse_lazy('blog:postlist') # reverse('postlist')와 차이점은 lazy는 지연을 줘서 DB에 적용이 될 때 까지 기다린후 이동한다.
class PostUpdate(UpdateView):
model = Post
fields = '__all__'
success_url = reverse_lazy('blog:postlist')
class PostDelete(DeleteView):
model = Post
success_url = reverse_lazy('blog:postlist')
# 변수에 할당
postlist = PostList.as_view() # as_view는 인스턴스를 생성하는 진입 메소드
postdetail = PostDetail.as_view()
write = PostCreate.as_view()
edit = PostUpdate.as_view()
delete = PostDelete.as_view()
blog / templates / blog 안에 html 파일 추가
Django에서 CBV(Class-Based Views)를 사용할 때, template_name을 따로 지정하지 않으면 템플릿 이름과 템플릿에서 접근 방법은 다음과 같은 규칙을 따른다.
ListView
템플릿 이름 : <app_name>/<model_name_소문자>_list.html
템플릿에서 접근 : {{ object_list }}
DetailView
템플릿 이름 : <app_name>/<model_name_소문자>_detail.html
템플릿에서 접근 : {{ object }}
CreateView
템플릿 이름 : <app_name>/<model_name_소문자>_form.html
템플릿에서 접근 : {{ form }}
UpdateView
템플릿 이름 : <app_name>/<model_name_소문자>_form.html
템플릿에서 접근 : {{ form }}
DeleteView
템플릿 이름 : <app_name>/<model_name_소문자>_confirm_delete.html
템플릿에서 접근 : {{ object }}
blog / post_list.html
<h2>Post List</h2>
<ul>
{% for post in object_list %}
<li>
<p><a href="{% url 'blog:postdetail' post.pk %}">{{ post.title }}</a></p>
<p>{{ post.content }}</p>
</li>
{% endfor %}
</ul>
blog / post_detail.html
<h2>{{ object.title }}</h2>
<p>{{ object.content }}</p>
<a href="{% url 'blog:edit' object.pk %}">수정</a>
<a href="{% url 'blog:delete' object.pk %}">삭제</a>
blog / post_form.html
<h2>Create / Update</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">저장</button>
</form>
blog / post_confirm_delete.html
<form method="post">
{% csrf_token %}
<p>"{{ object.title }}" 글을 정말 삭제하시겠습니까?</p>
<p><a href="{% url 'blog:postdetail' object.pk %}">취소</a></p>
<button type="submit">네</button>
</form>
검색 기능 추가
blog / post_list.html
<h2>Post List</h2>
<form action="" method="get"> # 검색 폼 추가
<input name="q" type="search">
<button type="submit">검색</button>
</form>
<ul>
{% for post in object_list %}
<li>
<p><a href="{% url 'blog:postdetail' post.pk %}">{{ post.title }}</a></p>
<p>{{ post.content }}</p>
</li>
{% endfor %}
</ul>
blog / views.py 수정
from django.db.models import Q # 위에 추가
class PostList(ListView):
model = Post
ordering = '-pk'
def get_queryset(self): # get요청 받으면 쿼리셋을 리턴
queryset = super().get_queryset() # 상속받는 ListView의 get_queryset 메서드 사용 (전체 반환)
# request의 GET 파라미터에서 'q'를 가져옴
q = self.request.GET.get('q', '')
# 'q' 파라미터가 있으면, 필터링
if q:
queryset = queryset.filter(Q(title__icontains=q) | Q(content__icontains=q))
return queryset
Admin 페이지의 Post 관리페이지에서 보이는거 수정하기
python manage.py createsuperuser 로 admin생성
blog / admin.py
from django.contrib import admin
from .models import Post
class PostAdmin(admin.ModelAdmin):
list_display = ['id', 'title', 'content', 'created_at', 'updated_at'] # Post 관리페이지에서 보이게 할거
admin.site.register(Post, PostAdmin)
'Django' 카테고리의 다른 글
Django 템플릿 필터 (1) | 2023.10.17 |
---|---|
Django CBV - 제네릭 뷰 (Generic View) (1) | 2023.10.16 |
Django 실습(6) Login 기능 구현하기 (0) | 2023.10.13 |
Django 실습(5) Form과 ModelForm 사용한 블로그 (0) | 2023.10.12 |
Django ORM을 이용해서 DB CRUD 해보기 (0) | 2023.10.11 |