混合搜索在各大網站如京東、淘寶都有應用,他們的原理都是什麼呢?本博文將爲你介紹它們的實現過程。css
混合搜索的原理,用一句話來講就是:關鍵字id進行拼接。html
視頻方向:前端
class Direction(models.Model): weight = models.IntegerField(verbose_name='權重(按從大到小排列)', default=0) name = models.CharField(verbose_name='名稱', max_length=32) classification = models.ManyToManyField('Classification') class Meta: db_table = 'Direction' verbose_name_plural = u'方向(視頻方向)' def __str__(self): return self.name
視頻分類:python
class Classification(models.Model): weight = models.IntegerField(verbose_name='權重(按從大到小排列)', default=0) name = models.CharField(verbose_name='名稱', max_length=32) class Meta: db_table = 'Classification' verbose_name_plural = u'分類(視頻分類)' def __str__(self): return self.name
視頻:數據庫
class Video(models.Model): status_choice = ( (0, u'下線'), (1, u'上線'), ) level_choice = ( (1, u'初級'), (2, u'中級'), (3, u'高級'), ) status = models.IntegerField(verbose_name='狀態', choices=status_choice, default=1)#可用於管理員的審覈 level = models.IntegerField(verbose_name='級別', choices=level_choice, default=1) classification = models.ForeignKey('Classification', null=True, blank=True) weight = models.IntegerField(verbose_name='權重(按從大到小排列)', default=0) title = models.CharField(verbose_name='標題', max_length=32) summary = models.CharField(verbose_name='簡介', max_length=32) img = models.ImageField(verbose_name='圖片', upload_to='./static/images/Video/') href = models.CharField(verbose_name='視頻地址', max_length=256) create_date = models.DateTimeField(auto_now_add=True) class Meta: db_table = 'Video' verbose_name_plural = u'視頻' def __str__(self): return self.title
備註:django
默認url:後端
http://127.0.0.1:8000/video-0-0-0.html,其中第一個數字表明視頻方向,默認0表明所有方向;第二個數字表明視頻分類,默認0表明所有分類;第三個數字表明視頻等級,默認0表明所有等級。安全
每個a標籤默認的url:app
例如運維自動化:<a href="/video-1-0-0.html">運維自動化</a>,即視頻方向的對應數字爲1,視頻分類和視頻等級都爲0,這樣作的目的是爲了將此url和用戶當前url進行拼接,並跳轉到新的url。運維
選擇運維自動化後的url:
多選狀況下的url:
{% load xx %}
注:
關於自定義simple_tag的更多信息,詳見下文。
<style> a{ display: inline-block; padding: 8px; } .active{ background-color: coral; color: white; } .item{ display: inline-block; width: 300px; height: 400px; } .item img{ border: 0; width: 300px; height: 280px; overflow: hidden; } </style>
設置css目的,當用戶選擇視頻方向、視頻分類、視頻等級時,加深對應a標籤。
<h3>選擇:</h3> <div> {% action_all current_url 1 %} : {% for item in direction_list %} {% action current_url item 1 %} {% endfor %} </div> <div> {% action_all current_url 2 %} : {% for item in class_list %} {% action current_url item 2 %} {% endfor %} </div> <div> {% action_all current_url 3 %} : {% for item in level_list %} {% action current_url item 3 %} {% endfor %} </div> <hr />
該區域所有基於自定義simple_tag實現,詳見下文。
視頻顯示區域html:
<h3>視頻:</h3> <hr /> {% for item in video_list %} <a class="item" href="{{ item.href }}"> <img src="/{{ item.img }}"> <p>{{ item.title }}</p> <p>{{ item.summary }}</p> </a> {% endfor %}
循環顯示符合條件的所有視頻。
咱們但願,當用戶選擇所有標籤時,url對應位置爲0,即當用戶三個選擇都是所有時,url爲:/video-0-0-0.html
以視頻方向爲例介紹:
對應位置html:
{% action_all current_url 1 %} :
從上述html可看出,action_all爲對應的函數,它接收兩個參數:當前url(current_url)、當前位置(視頻方向、視頻分類、視頻等級)。其中current_url是後臺傳入html的,詳見下文後臺views函數介紹。
action_all函數:
#!/usr/bin/env python # -*- coding:utf-8 -*- from django import template from django.utils.safestring import mark_safe @register.simple_tag #註冊simple_tag def action_all(current_url,index): #接收當前url和對應的位置參數 """ 獲取當前url,video-1-1-2.html :param current_url: :param item: :return: """ url_part_list = current_url.split('-') #根據「-」進行分割 if index == 3: #若是是視頻等級 if url_part_list[index] == "0.html": #若是選擇的是所有 temp = "<a href='%s' class='active'>所有</a>" #添加 「active」屬性 else: temp = "<a href='%s'>所有</a>" url_part_list[index] = "0.html" else: if url_part_list[index] == "0": temp = "<a href='%s' class='active'>所有</a>" else: temp = "<a href='%s'>所有</a>" url_part_list[index] = "0" href = '-'.join(url_part_list) #處理後的列表再拼接成url字符串 temp = temp % (href,) #生成對應的a標籤 return mark_safe(temp) #返回原生html
以視頻方向爲例介紹:
對應位置html:
{% action current_url item 1 %}
從上述html可看出:action函數接收三個參數 當前url、當前標籤對象、當前位置。
action函數:
@register.simple_tag def action(current_url, item,index): # videos-0-0-1.html # item: id name # video- 2 -0-0.html url_part_list = current_url.split('-') if index == 3: if str(item['id']) == url_part_list[3].split('.')[0]: #若是當前標籤被選中 temp = "<a href='%s' class='active'>%s</a>" else: temp = "<a href='%s'>%s</a>" url_part_list[index] = str(item['id']) + '.html' #拼接對應位置的部分url else: if str(item['id']) == url_part_list[index]: temp = "<a href='%s' class='active'>%s</a>" else: temp = "<a href='%s'>%s</a>" url_part_list[index] = str(item['id']) ur_str = '-'.join(url_part_list) #拼接總體url temp = temp %(ur_str, item['name']) #生成對應的a標籤 return mark_safe(temp) #返回安全的html
至此,全部選擇標籤生成完畢,可以根據用戶選擇動態生成url。
{% for item in video_list %} <a class="item" href="{{ item.href }}"> <img src="/{{ item.img }}"> <p>{{ item.title }}</p> <p>{{ item.summary }}</p> </a> {% endfor %}
循環顯示全部符合條件的視頻。
def video(request,*args,**kwargs): print(kwargs) print(request.path) request_path = request.path #當前請求的路徑 q = {} #從數據庫獲取視頻時的filter條件字典 q['status'] = 1 #狀態爲審覈經過的 class_id = int(kwargs.get('classification_id')) #獲取url中的視頻分類id direction_list = models.Direction.objects.all().values('id','name') #從數據庫中獲取全部的視頻方向(包括視頻方向的id和name) if kwargs.get('direction_id') == '0': # 方向選擇所有 print('方向等於0') class_list = models.Classification.objects.all().values('id', 'name') #方向id=0,即獲取全部的視頻分類(包括視頻分類的id和name) if kwargs.get('classification_id') == '0': #若是視頻分類id也爲0,即所有分類 pass else: # 若是視頻分類不是所有,過濾條件爲視頻分類id in [url中的視頻分類id] q['classification_id__in'] = [class_id,] else: print('方向不爲0') # 方向選擇某一個方向, # 若是分類是0 if kwargs.get('classification_id') == '0': print('分類爲0') obj = models.Direction.objects.get(id=int(kwargs.get('direction_id'))) #獲取已選擇的視頻方向 class_list = obj.classification.all().values('id', 'name') #獲取該方向的全部視頻分類 id_list = list(map(lambda x: x['id'], class_list)) #獲取全部視頻分類對應的視頻分類id q['classification_id__in'] = id_list #過濾條件爲視頻分類id in [該方向下的全部視頻分類id] else: #方向不爲0,分類也不爲0 obj = models.Direction.objects.get(id=int(kwargs.get('direction_id'))) class_list = obj.classification.all().values('id', 'name') id_list = list(map(lambda x:x['id'], class_list)) q['classification_id__in'] = [class_id,] #過濾條件爲視頻分類id in [已經選擇的視頻分類id] print('分類不爲0') # 當前分類若是在獲取的全部分類中,則方向下的全部相關分類顯示 # 當前分類若是不在獲取的全部分類中, if int(kwargs.get('classification_id')) in id_list: pass else: print('再也不,獲取指定方向下的全部分類:選中的回到所有') url_part_list = request_path.split('-') url_part_list[2] = '0' request_path = '-'.join(url_part_list) level_id = int(kwargs.get('level_id')) #視頻等級id if level_id == 0: pass else: q['level'] = level_id #過濾條件增長視頻等級 # models.Video.objects.filter(status=1) video_list = models.Video.objects.filter(**q).values('title','summary', 'img', 'href') # level_list = models.Video.level_choice ret = map(lambda x:{"id": x[0], 'name': x[1]}, models.Video.level_choice)#把視頻等級轉化爲單個標籤是字典格式,總體是列表格式 level_list = list(ret) return render(request, 'video.html', {'direction_list': direction_list, 'class_list': class_list, 'level_list': level_list, 'current_url': request_path, "video_list": video_list})
總結:以上就是混合搜索的先後端全過程,歡迎讀者來與樓主進行交流。若是本文對您有參考價值,歡迎幫博主點下文章下方的推薦,謝謝!