-
Day-2(Signal, get_object & get_queryset, form)TIL & Todo List/Coding for Entrepreneures 2020. 1. 13. 00:25
Signal(pre_save & post_save)을 이용한 SlugField
- django의 Signal은 특정 메서드나 함수가 실행될 때 일어나는 신호(signal)를 받아서 추가 작업을 진행할 수 있도록 한다.
- 예) 모델이 저장될 시점의 전(pre_save), 후(post_save)에 추가적인 작업을 구현할 수 있다.
- Signal은 signal을 정의한 모델을 사용하는 모든 앱에서 동작한다.
- videos에 정의된 모델(signal을 포함하는)을 다른 앱에서 저장하거나 업데이트를 할 때 signal이 동작한다.
- pre_save, post_save 외에 model signal, management signal, request/response signal 등 다양한 signal이 있다.
SlugField는 url에서 look up field로 사용될 수 있으며, 웹 검색 시 SEO(Search Engine Optimization)을 향상하는데 도움을 준다.
# modles.py # pre_save() def pre_save_video_receiver(sender, instance, *args, **kwargs): instance.slug = slugify(instance.title) pre_save.connect(pre_save_video_receiver, sender=Video) # post_save() def post_save_video_receiver(sender, instance, *args, **kwargs): instance.slug = slugify(instance.title) instance.save() # 무한 재귀가 일어남 post_save.connect(post_save_video_receiver, sender=Video) # decorator를 이용한 pre_save() @receiver(pre_save, sender=Video) def pre_save_video_receiver(sender, instance, *args, **kwargs): instance.slug = slugify(instance.title)
- SlugField를 자동으로 채우기 위해 signal을 이용할 수 있다.
- slugify(django.utils.text.slugify): 입력된 매개변수를 slug 형태로 변환시켜주는 메서드
- pre_save()는 slug를 생성하고 이를 instance.slug에 할당하고 이후에 save()
- post_save()는 instance.save()가 일어난 후 slug를 생성하고 instance.slug에 할당하기 때문에 database에 slug가 저장되지 않는다.
- instance.save()를 post_save안에 등록할 경우 save 호출 -> post_save호출 -> save호출.... 무한 재귀가 일어난다.
- 따라서 instance의 필드에 추가로 변경된 값을 저장해야 할 경우 pre_save()를 이용해야 한다.
Overriding get_object
get_object(): 응답에 필요한 객체를 가져오기 위해 사용되는 메서드
# views.py class VideoDetailView(DetailView): queryset = Video.objects.all() # get_object를 오버라이딩 하지 않을 경우 자동으로 url에서 id 또는 slug를 검색하고 해당 객체를 반환한다. def get_object(self, queryset=None): slug = self.kwargs.get('slug') return get_object_or_404(Video, slug=self.kwargs.get(slug)) # urls.py urlpatterns =[ ... path('videos/<slug>', VideoDetailView.as_view(), name='video-detail'), ]
- self.kwargs.get('slug')는 urls.py에 등록된 path의 slug를 의미한다.
- self.kwargs -> django.views.generics.base.View
get_queryset(): 응답에 필요한 쿼리셋을 가져오기 위해 사용되는 메서드
class VideoListView(ListView): # queryset = Video.objects.all() # -> Video의 모든 객체 def get_queryset(self): # Video에서 title에 'django'를 포함하는 모든 객체 return Video.objects.filter(title__icontains='django')
- get_queryset()을 오버 라이딩하여 사용자가 원하는 쿼리 셋을 가져오기 위한 동작을 구성할 수 있다.
Form(공식 문서) - CreateView, UpdateView, DeleteView
- ListView와 DetailView는 클라이언트가 요청한 객체를 전달하기 위해 queryset 또는 get_object를 이용한다. 이와 달리 Create, Update, Delete 작업을 위한 클래스에서는 queryset이 아닌 model 속성을 등록해서 사용한다.
- POST를 사용할 때 csrf_token(공식 문서) 태그를 반드시 사용해야 한다.
- Cross Site Request Forgery(CSRF): 사용자가 의도한 요청이 아닌, 외부 유저(해커)가 사이트에 요청을 대신 전달하게 하는 공격 방식
- csrf_token은 페이지에 접속할 때 유저에게 token을 전달하고 post 동작이 필요할 때 django가 유저의 token을 검사하는 방식을 사용한다.
- 게시글을 작성하기 위한 페이지에 접속(유저는 token_a 획득)
- 글 작성을 위한 POST 실행
- django에서 토큰 확인(token_a? token_b?)
(중간 과정에서 해커가 접속하여 다른 동작(공격)을 시도하더라도 토큰(token_a)을 가지고 있지 않기 때문에 공격 불가)
# views.py class VideoCreateView(CreateView): # queryset = Video.objects.all() # ImproperlyConfigured 에러를 일으킨다. model = Video form_class = VideoForm # forms.py class VideoForm(forms.ModelForm): class Meta: model = Video fields = [ 'title', 'embed_code' ] # templates/video_create.html(content 블록) {% block content %} <h1>Hello!!</h1> <form method="POST" action="" > {% csrf_token %} {{ form.as_p }} <input type="submit" value="Save" class="btn btn-primary"> </form> {% endblock %}
Search view
get 메서드를 이용한 검색 기능 구현
# views.py class VideoListView(ListView): def get_queryset(self): q = self.request.GET.get('q') qs = Video.objects.all() if q: # query string이 있을 경우 qs = qs.filter(title__icontains=q) return qs # templates/video_list.py ... <form method="GET" action="{% url 'video-list' %}"> <input type="text" placeholder="Search.." name="q"> </form> {{ object_list }} <ul> {% for item in object_list%} <li> <a href="{{ item.get_absolute_url }}"> {{ item.title}} </a></li> {% empty %} <li>No item Found</li> {% endfor %} </ul>
self.request.GET.get('q'): 요청(get)한 url의 q(query string)에 포함된 단어를 검색어로 사용한다. 검색 입력 창에 단어를 입력 후 엔터를 칠 경우, template의 method(GET)가 동작한다.
title__icontains=query: 검색에 사용될 대상 필드를 찾기위해 사용되는 구문(Django-Field lookups). <필드명>__<Field lookups>로 구성된 키워드 인수이며, icontains 외에 필터 기능에 따라 여러가지 lookup이 존재한다. Field lookup 구문은 SQL에서 'WHERE'절에 해당한다.
name='q': url에 사용될 query string을 담을 변수 명을 지정한다.
{% empty %}: empty tag를 이용해 for 구문에서 조건에 맞는 객체를 찾지 못할 경우(비어있을 경우) 출력할 값 또는 문구를 지정할 수 있다.
'TIL & Todo List > Coding for Entrepreneures' 카테고리의 다른 글
- django의 Signal은 특정 메서드나 함수가 실행될 때 일어나는 신호(signal)를 받아서 추가 작업을 진행할 수 있도록 한다.