2019.05.13 장고 페이지 서칭 기능 구현하기
서칭 기능 구현하기
- 데이터베이스에 질의문 (query 문)/ 애초에 해당애들만 뽑아오기
- documents = Document.objects.filter(title__contains = "1")
- documents = get_list_or_404(Document, title__contains = "1")
- 코드레벨 검색 (DB에서 다 가지고 온 다음에 뽑아내기 )
- 파이썬 코드레벨에서 검색
- 다 가지고 온 다음에 for문 같은 것을 돌려야 한다.
- DB에서 가지고 오는게 제일 빠른데 항상 병목 현상은 db에서 발생한다.
- 서비스가 느려지고 그럴 수 있다.
- 데이터베이스의 쿼리질의문을 줄인다.?
- 하나씩 물어보는 방법과 한번에 물어보는 방법이 있다.
- 하지만 그렇게 하면 질의문이 길어져서 해석하는데 시간이 오래 걸릴 수 있다.
로직 생각
- 검색어가 들어온다.
- 검색어를 받아서 제대로 받았는지 확인한다.
- filter 메소드를 사용한다.
- 어떤 항목을 검색할 것이냐?
- 내용/ 작성자 등
- 어떤 옵션으로 검색할 것이냐?
- 특정단어가 들어가있는지/ 처음에 시작하는지/ 대문자 / 소문자 등등
쉘에서 filter 연습하기
- objects는 manage이다. 모델명.objects. 인 경우
- filter( a, b) : a이고 b 인것
- filter(filed이름) = 매칭
- filter(필드이름__옵션)
- filter(title__startswitch = "") : 제목이 특정 문구로 시작하는 것
- (title__istartswitch) : 제목이 대소문자 구분 없이 특정 문구로 시작
- "" % : 뒤에 특정 애들이 붙을 수 있다.
- filter(title__endswitch = "") : 특정 문구로 끝나는지
- filter(title__iexact=="" ) : 대소문자 구분없이 특정 제목이 있나?
- filter(title__icontains = "") : 대소문자 구분없이 중간에 포함하고 있나?
- 우리가 이렇게 매칭한 것은 로컬필드가 검색이 가능하다.
- 기본 필드들이 로컬 필드 이다.
- 그럼 연결된 foreign key혹은 primary key는 어떻게 해야하나?
- filter(category__name="c1") : 카테고리 필드의 이름이 c1인 것
- filter(category__ name__endswith =" ") : 카테고리의 이름이 "" 으로 끝나는 애들
- %endswith : 앞에 특정 애들이 붙을 수 있다.
- 여러개 모델에서 찾는 것도 추가적으로 구현할 수 있다.
- by 일래스틱서치 - 우리의 스팩이 한줄 더 늘 수 있다.
- 한글 검색이 특히
정리(위의 예시를 바탕으로 정리한 것입니다)
- 필드명 = "값" 매칭
- 필드명__exact = "값" 매칭
- 필드명__iexact = "값" 대소문자 구분 없이 매칭
- 필드명__ startswich,필드명 __istartswich : "값"으로 시작
- 필드명__ endswitch, 필드명__iendswitch : "값"으로 끝
- 필드명__ contains , 필드명__icontains : "값"을 포함하느냐?
- Foreignkey 매칭
- 필드명__해당모델의 필드명 : 매칭
- 필드명__ 해당모델의 필드명__ 옵션 : 해당 모델의 필드명이 해당 옵션으로 매칭
- 필드명__ gt=값, 필드명__gte= 값 크다, 크거나 같다.
- ex) created__gt = 오늘 : 작성일이 오늘보다 크다. (오늘 00시 이후)
- 필드명__ lt =값 , 필드명__lte = 값 작다, 작거나 같다.
- ex) created__lt = 오늘 : 작성일이 오늘보다 이전이다. (datetime.now())
- ex) 판매시작일 __lt = 오늘 : 판매시작일 설정값이 오늘보다 작거나 같으면 판매시작
서칭 버튼 구현 (템플릿)
서칭 views.py 구현
- 서칭은 기본적으로 list를 띄어주는 상황에서 가능하다.
- search_key가 없으면 그냥 get_list를 통해 모든 list를 가지고 온다.
서칭 심화 구현 - OR 구현하기
- 특정 필드가 아닌 제목, 본문, 사용자이름과 관련해서 동시에 서칭하고 싶을 때!
Q 객체 사용하기
>>> from django.db.models import Q
>>> Q(title__icontains='1')
<Q: (AND: ('title__icontains', '1'))>
>>> default_q = Q(title__icontains='1')
>>> second_q = Q(text__icontains='1')
>>> default_q | second__q
<Q: (OR: ('title__icontains', '1'), ('text__icontains', '1'))>
>>> Document.objects.filter(default_q|second_q)
Q객체는 우리가 기존에 쓰던 필터를 그대로 쓰게 해주는데, 일반 필더안에서는 and만 가능해서 Q객체를 활용해서 or을 사용가능하게 된다.
- objects.filter() : filter 매서드에 들어가는 매개변수들은 항상 and 연산을 한다.
- or 연산을 하고 싶퍼서 Q객체를 사용한다.
- 사용법은 filter에 들어가는 매개변수의 작성법과 똑같다.
- Q() | Q() : OR
- Q() & Q() : AND
- ~Q() :NOT
- 구글 검색 연산자
- 작성자, 제목, 본문에 대해서 다 검색할 수 있도록
- 체크박스 보이기
- 체크박스 값확인
- Q객체를 어떻게 만들 것인가?
제목, 본문에서 해당 내용 같이 검색하도록 하기 (by Q객체 - views.py)
- title_q와 text_q를 변수로 받고 Q 객체를 활용하여 OR 필터가 가능하도록 한다.
- 그 이외는 모두 한개의 필터를 사용할 때와 같다.
체크박스로 작성자/ 제목/ 내용 등을 구분할 때
views.py 구현하기
- request.METHOD.get : 마지막 들어오는 1개만 표시
- request.METHOD.getlist : 리스트 형태로 모두 가지고 온다.
- search_type = request.GET.getlist('search_type',None)
- 기본적으로 search_type이 없으면 text에서 검색하도록 한다.
- 각각 title/ text/ username이 들어왔을 때에 따라서 분기하여 구현한다.
templates 구현하기
- form을 get 방식으로 받아오고 3가지를 모두 search_type이라는 이름으로 받아온다.
- 따라서 views.py에서 getlist를 통해 모두 가지고 와야 한다.