组合搜索其实就是网页中组合多个条件,对数据库中进行查询,并且将结果显示在页面中,如下:
可以看到我们红框部分,是根据URL来做组合搜索的
这里是以视频为例, video-1-1-0.html 后面三位数字的含义 第一位数字: 视频方向 id 第二位数字: 视频类型 id 第三位数字: 视频难度 id
代码分析:
url.py部分,我们需要用正则匹配
re_path('^video-(?P<direction_id>d+)-(?P<classes_id>d+)-(?P<level_id>d+).html',views.video) #这里有分为3组都为数字的数据direction_id(方向ID)、classes_id(类型ID)、level_id(级别难度id),会直接作为参数传递到views.video函数
解释下上面正则 1、这里的(?P<name>...) 和普通的(?...): 基本类似。区别在于,此处由于是给此group命名了,所有后续(同一正则表达式内和搜索后得到的Match对象中),都可以通过此group的名字去引用此group 2、同一正则表达式内,每个group组名是唯一的,不能重复
表结构 models.py
1 class Direction(models.Model): 2 ''' 3 视频方向 4 ''' 5 state_choice = ( 6 (0, '展示'), 7 (1, '不展示'), 8 ) 9 name = models.CharField(max_length=32,verbose_name='视频方向') 10 classes = models.ManyToManyField('Classes') 11 state = models.SmallIntegerField(choices=state_choice,default=0,verbose_name='方向状态') 12 13 class Meta: 14 db_table = 'direction' 15 verbose_name_plural = '视频方向' 16 17 def __str__(self): 18 return self.name 19 20 class Classes(models.Model): 21 ''' 22 视频类别 23 ''' 24 state_choice = ( 25 (0, '展示'), 26 (1, '不展示'), 27 ) 28 name = models.CharField(max_length=32,verbose_name='视频分类') 29 state = models.SmallIntegerField(choices=state_choice,default=0,verbose_name='分类状态') 30 31 class Meta: 32 db_table = 'classes' 33 verbose_name_plural = '视频分类' 34 35 def __str__(self): 36 return self.name 37 38 class Video(models.Model): 39 ''' 40 视频信息 41 ''' 42 state_choice = ( 43 (0, '展示'), 44 (1, '不展示'), 45 ) 46 level = ( 47 (1,'初级'), 48 (2,'中级'), 49 (3,'高级'), 50 ) 51 title = models.CharField(max_length=32,blank=True,verbose_name='视频标题') 52 level_id = models.SmallIntegerField(choices=level,default=1,verbose_name='视频级别') 53 state = models.SmallIntegerField(choices=state_choice,default=0,verbose_name='视频状态') 54 href = models.CharField(max_length=256,verbose_name='视频链接') 55 jianjie = models.CharField(max_length=256,verbose_name='视频简介') 56 img = models.ImageField(upload_to='./static/img/video/',null=True,verbose_name='视频图片') 57 classes = models.ForeignKey('Classes',on_delete=models.CASCADE) 58 59 class Meta: 60 db_table = 'video' 61 verbose_name_plural = '视频信息' 62 63 def __str__(self): 64 return self.title
视频方向表和视频类别表是多对多关系
视频类别表和视频信息表是一对多关系
主逻辑 views.py
def video(request,*args,**kwargs): logo = models.Logo.objects.all().first() menu_nav = models.MenuNav.objects.all().order_by('-width') ''' 这里从kwargs 获取url上面匹配到的数字,用组名取值 ''' direction_id = int(kwargs['direction_id']) classes_id = int(kwargs['classes_id']) level_id = int(kwargs['level_id']) #定义一个空字典,用于最后结果的组合查询条件 contents = {} #视频方向是永远不会发生变化的,所以这里直接从数据库中取出来 direction_ls = models.Direction.objects.filter(state=0).values('id','name') ''' 判断url上的方向id 是否为 0 或者 方向id 不在 取出来的视频方向id里面: 就把url传过来的方向ID赋值为0(这里是当后面条件成立时有用), 获取所有的类型,然后判断 url 传过来的 类型id 是否为0 或者 类型id 不在取出来的类型id里面: 就把url传过来的类型id赋值为0 (同上), 然后把所有的类型ID 赋值给查询条件 contents['classes_id__in'] ,这里的classes_id__in 键值,是查询时候的键值 否则(类型id不为0,并且在取出来的类型id列表里面): 就把url取出来的类型id 赋值为 contents['classes_id'] 这里的classes_id 键值,是查询时候的键值 否则(方向id不为0,并且在取出来的方向id列表里面): 首先取出对应url方向id的所有类型 然后判断 url 传过来的 类型id 是否为0 或者 类型id 不在取出来的类型id里面: 就把url传过来的类型id赋值为0 (同上), 然后把所有的类型ID 赋值给查询条件 contents['classes_id__in'] ,这里的classes_id__in 键值,是查询时候的键值 否则(类型id不为0,并且在取出来的类型id列表里面): 就把url取出来的类型id 赋值为 contents['classes_id'] 这里的classes_id 键值,是查询时候的键值 ''' if direction_id == 0 or direction_id not in [i['id'] for i in direction_ls]: direction_id = 0 class_ls = models.Classes.objects.all().values_list('id','name') if classes_id == 0 or classes_id not in [i[0] for i in class_ls]: classes_id = 0 contents['classes_id__in'] = [i[0] for i in class_ls] else: contents['classes_id'] = classes_id else: class_ls = models.Direction.objects.filter(id=direction_id).values_list('classes__id','classes__name') if classes_id == 0 or classes_id not in [i[0] for i in class_ls]: classes_id = 0 contents['classes_id__in'] = [i[0] for i in class_ls] else: contents['classes_id'] = classes_id level_ls = models.Video.level if level_id != 0 : contents['level_id'] = level_id contents['state'] = 0 result = models.Video.objects.filter(**contents) return render(request,'video.html',{ 'menu_nav':menu_nav, 'Logo':logo, 'direction_id':direction_id, 'classes_id':classes_id, 'level_id':level_id, 'direction_ls':direction_ls, 'class_ls':class_ls, 'level_ls':level_ls, 'result':result })
前端 video.html,这里就没有截取样式的图了
{% extends 'base.html' %} {% block head_content %}{% endblock %} {% block content %} <div class="video_select"> <ul> <p>方向:</p> {% if direction_id == 0 %} <li><a class="active" href="video-0-{{ classes_id }}-{{ level_id }}.html">全部</a></li> {% else %} <li><a href="video-0-{{ classes_id }}-{{ level_id }}.html">全部</a></li> {% endif %} {% for i in direction_ls %} {% if i.id == direction_id %} <li><a class="active" href="video-{{ i.id }}-{{ classes_id }}-{{ level_id }}.html">{{ i.name }}</a></li> {% else %} <li><a href="video-{{ i.id }}-{{ classes_id }}-{{ level_id }}.html">{{ i.name }}</a></li> {% endif %} {% endfor %} </ul> <ul > <p>分类:</p> {% if classes_id == 0 %} <li><a class="active" href="video-{{ direction_id }}-0-{{ level_id }}.html">全部</a></li> {% else %} <li><a href="video-{{ direction_id }}-0-{{ level_id }}.html">全部</a></li> {% endif %} {% for i in class_ls %} {% if i.0 == classes_id %} <li><a class="active" href="video-{{ direction_id }}-{{ i.0 }}-{{ level_id }}.html">{{ i.1 }}</a></li> {% else %} <li><a href="video-{{ direction_id }}-{{ i.0 }}-{{ level_id }}.html">{{ i.1 }}</a></li> {% endif %} {% endfor %} </ul> <ul> <p>难度:</p> {% if level_id == 0 %} <li><a class="active" href="video-{{ direction_id }}-{{ classes_id }}-0.html">全部</a></li> {% else %} <li><a href="video-{{ direction_id }}-{{ classes_id }}-0.html">全部</a></li> {% endif %} {% for i in level_ls %} {% if i.0 == level_id %} <li><a class="active" href="video-{{ direction_id }}-{{ classes_id }}-{{ i.0}}.html">{{ i.1 }}</a></li> {% else %} <li><a href="video-{{ direction_id }}-{{ classes_id }}-{{ i.0 }}.html">{{ i.1 }}</a></li> {% endif %} {% endfor %} </ul> </div> <div class="video-content"> <div class="row"> {% for i in result %} <div class="col-xs-3"> <img src="{{ i.img }}" style=" 150px;height: 120px" alt=""> <p>{{ i.title }}</p> </div> {% endfor %} </div> </div> {% endblock %}