Django 标签筛选的实现(一对多、多对多)
实现的目标(一对多)
实现针对课程实现:课程类型、难度级别、是否隐藏三个方式的筛选
每一个视频文件有针对一个课程类型、一个难度级别、是否隐藏
设计数据库如下:
![](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
# 视频分类表格 class VideoType(models.Model): Video_Type = models.CharField(max_length=50) class Meta: verbose_name_plural = \'视频分类\' def __str__(self): return self.Video_Type # 视频难度表格 class VideoDif(models.Model): Video_dif = models.CharField(max_length=50) class Meta: verbose_name_plural = \'视频难度\' def __str__(self): return self.Video_dif # 视频:ID、视频图片、视频名称、视频简介、视频地址、视频分类、视频难度、权重、是否显示 class Video(models.Model): Video_img = models.CharField(max_length=100) Video_title = models.CharField(max_length=100) Video_text = models.TextField() Video_type_id = models.ForeignKey(\'VideoType\', on_delete=models.CASCADE,) Video_dif_id = models.ForeignKey(\'VideoDif\', on_delete=models.CASCADE,) Video_qz = models.IntegerField(default=0) display_choice = ( (1, \'显示\'), (2, \'隐藏\'), ) display = models.IntegerField(verbose_name=\'状态\', choices=display_choice, default=1) class Meta: verbose_name_plural = \'视频\'
URL文件:
![](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
from django.urls import re_path urlpatterns = [ path(\'admin/\', admin.site.urls), path(\'video/\', views.video), # 通过正则表达式添加三个字段,从前台获取当前选择项 re_path(\'video-(?P<Video_type_id>(\d+))-(?P<Video_dif_id>(\d+))-(?P<display>(\d+))\', views.video),
后台程序文件:
![](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
def video(request,*args,**kwargs): # 给后台筛选数据库使用 condition = {} # kwargs是从前台URL获取的键值对,如果第一次访问,针对字典做一个初始化 if not kwargs: kwargs ={ \'Video_type_id\':0, \'Video_dif_id\':0, \'display\':0, } # 依次取出kwargs字典中传来的值 for k, v in kwargs.items(): # 首先将传来的值变为数字类型 temp = int(v) kwargs[k] = temp # 如果kwargs中有值,循环将值赋予condition列表 if temp: condition[k] = temp # 从数据库中获取视频类型的列表 VideoType_list = models.VideoType.objects.all() # 从数据库中获取视频难度的列表 VideoDif_list = models.VideoDif.objects.all() # 从数据库中视频列表中,获取是否显示的字段的内容,是一个元组形式的:((1, \'显示\'), (2, \'隐藏\')) # map后形成一个map对象:{\'id\':1,\'name\':\'显示\'} # 最后list转换为列表:[{\'id\': 1, \'name\': \'显示\'}, {\'id\': 2, \'name\': \'隐藏\'}] display_list = list(map(lambda x:{\'id\':x[0],\'name\':x[1]},models.Video.display_choice)) # 根据condition列表筛选数据库中的视频列表 video_list = models.Video.objects.filter(**condition) return render( request, \'video1.html\', { \'VideoType_list\': VideoType_list, \'VideoDif_list\': VideoDif_list, \'kwargs\': kwargs, \'video_list\': video_list, \'display_list\': display_list, } )
前台展示文件:
![](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .condition a{ display: inline-block;; padding: 5px 8px; border: 1px solid #dddddd; } .condition a.active{ background-color: red; color: white; } </style> </head> <body> <div class="condition"> <h1>筛选</h1> <div> {% if kwargs.Video_type_id == 0%} <a href="/video-0-{{ kwargs.Video_dif_id }}-{{ kwargs.display }}" class="active">全部</a> {% else %} <a href="/video-0-{{ kwargs.Video_dif_id }}-{{ kwargs.display }}">全部</a> {% endif %} {% for i in VideoType_list %} {% if i.id == kwargs.Video_type_id %} <a href="/video-{{ i.id }}-{{ kwargs.Video_dif_id }}-{{ kwargs.display }}" class="active">{{ i.Video_Type }}</a> {% else %} <a href="/video-{{ i.id }}-{{ kwargs.Video_dif_id }}-{{ kwargs.display }}">{{ i.Video_Type }}</a> {% endif %} {% endfor %} </div> <div> {% if kwargs.Video_dif_id == 0%} <a href="/video-{{ kwargs.Video_type_id }}-0-{{ kwargs.display }}" class="active">全部</a> {% else %} <a href="/video-{{ kwargs.Video_type_id }}-0-{{ kwargs.display }}">全部</a> {% endif %} {% for i in VideoDif_list %} {% if i.id == kwargs.Video_dif_id %} <a href="/video-{{ kwargs.Video_type_id }}-{{ i.id }}-{{ kwargs.display }}" class="active">{{ i.Video_dif }}</a> {% else %} <a href="/video-{{ kwargs.Video_type_id }}-{{ i.id }}-{{ kwargs.display }}">{{ i.Video_dif }}</a> {% endif %} {% endfor %} </div> <div> {% if kwargs.display == 0 %} <a class="active" href="/video-{{ kwargs.Video_type_id }}-{{ kwargs.Video_dif_id }}-0">全部</a> {% else %} <a href="/video-{{ kwargs.Video_type_id }}-{{ kwargs.Video_dif_id }}-0">全部</a> {% endif %} {% for item in display_list %} {% if item.id == kwargs.display %} <a class="active" href="/video-{{ kwargs.Video_type_id }}-{{ kwargs.Video_dif_id }}-{{ item.id }}">{{ item.name }}</a> {% else %} <a href="/video-{{ kwargs.Video_type_id }}-{{ kwargs.Video_dif_id }}-{{ item.id }}">{{ item.name }}</a> {% endif %} {% endfor %} </div> </div> <div> <h1>结果</h1> <div> {% for row in video_list %} <p>{{ row.Video_title }}</p> {% endfor %} </div> </div> </body> </html>
前台通过变化active标签,实现选中的显示,通过a标签中的数字控制后台筛选操作
实现的目标(多对多)
实现针对课程实现:课程方向、课程类型、难度级别三个方式的筛选
其中每个课程方向中包含有多个课程类型,选择课程方向后,筛选课程方向包含的所有课程类型
每一个视频文件有针对一个课程类型、一个难度级别
设计数据库如下,在一对多的基础上增加了一个多对多的课程方向表:
![](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
# 方向分类:ID、名称(与视频—分类做多对多关系) class VideoGroup(models.Model): Video_group = models.CharField(max_length=50) group_type = models.ManyToManyField(\'VideoType\') class Meta: verbose_name_plural = \'方向分类\' def __str__(self): return self.Video_group # 视频分类表格 class VideoType(models.Model): Video_Type = models.CharField(max_length=50) class Meta: verbose_name_plural = \'视频分类\' def __str__(self): return self.Video_Type # 视频难度表格 class VideoDif(models.Model): Video_dif = models.CharField(max_length=50) class Meta: verbose_name_plural = \'视频难度\' def __str__(self): return self.Video_dif # 视频:ID、视频图片、视频名称、视频简介、视频地址、视频分类、视频难度、权重、是否显示 class Video(models.Model): Video_img = models.CharField(max_length=100) Video_title = models.CharField(max_length=100) Video_text = models.TextField() Video_type_id = models.ForeignKey(\'VideoType\', on_delete=models.CASCADE,) Video_dif_id = models.ForeignKey(\'VideoDif\', on_delete=models.CASCADE,) Video_qz = models.IntegerField(default=0) display_choice = ( (1, \'显示\'), (2, \'隐藏\'), ) display = models.IntegerField(verbose_name=\'状态\', choices=display_choice, default=1) class Meta: verbose_name_plural = \'视频\'
URL文件:
![](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
urlpatterns = [ path(\'admin/\', admin.site.urls), path(\'video2/\', views.video2), re_path(\'video2-(?P<Video_group_id>(\d+))-(?P<Video_type_id>(\d+))-(?P<Video_dif_id>(\d+))\', views.video2), ]
后台程序文件:
![](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
def video2(request, *args, **kwargs): condition = {} # 思路 -- 构造查询字典 """ 如果:获取Video_group_id=0 代表方向是全部,不会对以后的筛选造成影响 *列出所有的type 如果:Video_type_id=0 pass 否则: condition【\'Video_type_id\'】= Video_type_id 否则:*列出当前方向下的type 如果:Video_type_id=0 获取当前方向下的type的所有的id【1,2,3,4】 condition【\'Video_type_id__in\'】= 【1,2,3,4】 否则: 需要查看当前的type是否在当前的方向列表中,如果在: condition【\'Video_type_id\'】= Video_type_id 如果不在: condition【\'Video_type_id__in\'】= 【1,2,3,4】 """ if not kwargs: kwargs = { \'Video_type_id\':0, \'Video_dif_id\':0, \'Video_group_id\':0, } for k, v in kwargs.items(): temp = int(v) kwargs[k] = temp # 首先从kwargs中取出相应的id group_id = kwargs.get(\'Video_group_id\') type_id = kwargs.get(\'Video_type_id\') dif_id = kwargs.get(\'Video_dif_id\') # 从数据库中取出所有的group列表,因为所有方向在页面上都要显示 group_list = models.VideoGroup.objects.all() # 判断group值是否为0 if group_id == 0: # 如果为0,则列出所有type的列表 VideoType_list = models.VideoType.objects.all() # 如果type的列表也为0,筛选中就不用作特殊操作 if type_id == 0: pass # 如果type的列表不为0,筛选列表中增加type的id else: condition[\'Video_type_id\'] = type_id # 如果group值不为0 else: # 首先根据group的id筛选出分类表格中的内容,形成一个对象 group_obj = models.VideoGroup.objects.filter(id=group_id).first() # 再根据group筛选出的对象,用多对多表格字段,筛选出所有的type的列表,等待返回给前台使用 VideoType_list = group_obj.group_type.all() # 获取筛选后的type的id值,得到一个QuerySet [(1,),(3,),(4,)]的对象 vlist = group_obj.group_type.all().values_list(\'id\') # 如果筛选后的type的值为空,也就是没有找到对应的type类型 if not vlist: # 设置一个空列表 type_ids = [] # 如果筛选后的type值有内容 else: # 将vlist进行一个zip,获得一个zip的对象,再转化为列表,得到一个【(1,3,4)】,取第一个值,得到(1,3,4) type_ids = list(zip(*vlist))[0] # (1,3,4) # 判断如果前台传来的type为0的话 if type_id == 0: # 后台筛选的时候,查询按照方向筛选出来的type_ids进行查询 # __in指的是用列表方式查询多个id condition[\'Video_type_id__in\'] = type_ids # 如果前台传来的type不为0的时候,有两种情况 else: # 如果前台传来的type值在后台筛选的值范围内的时候 if type_id in type_ids: # 后台筛选的typeid就按照前台传来的type值筛选,也就是前台选了某个课程,如果课程方向发生改变的时候,课程类型还在选择范围内,前台也仍然是选中的状态,我们也就仍然返回选中的课程类型筛选的内容 condition[\'Video_type_id\'] = type_id # 如果前台传来的type值不在后台筛选的值范围内的时候 else: # 就按照后台筛选的课程方向向下的所有type类型进行筛选 condition[\'Video_type_id__in\'] = type_ids kwargs[\'Video_type_id\'] = 0 # 难度这边跟上面的多对多没有关联,与一对多的情况时一样 if dif_id == 0: pass else: condition[\'Video_dif_id\'] = dif_id VideoDif_list = models.VideoDif.objects.all() # 最终将符合条件的视频筛选出来 video_list = models.Video.objects.filter(**condition) return render( request, \'video2.html\', { \'group_list\': group_list, \'VideoType_list\': VideoType_list, \'VideoDif_list\': VideoDif_list, \'video_list\': video_list, \'kwargs\': kwargs } )
前台展示文件:
![](https://image.shishitao.com:8440/aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vT3V0bGluaW5nSW5kaWNhdG9ycy9Db250cmFjdGVkQmxvY2suZ2lm.gif?w=700&webp=1)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .condition a{ display: inline-block;; padding: 5px 8px; border: 1px solid #dddddd; } .condition a.active{ background-color: red; color: white; } </style> </head> <body> <div class="condition"> <h1>筛选</h1> <div> {% if kwargs.Video_group_id == 0%} <a href="/video2-0-{{ kwargs.Video_type_id }}-{{ kwargs.Video_dif_id }}" class="active">全部</a> {% else %} <a href="/video2-0-{{ kwargs.Video_type_id }}-{{ kwargs.Video_dif_id }}">全部</a> {% endif %} {% for item in group_list %} {% if item.id == kwargs.Video_group_id %} <a class="active" href="/video2-{{ item.id }}-{{ kwargs.Video_type_id }}-{{ kwargs.Video_dif_id }}">{{ item.Video_group }}</a> {% else %} <a href="/video2-{{ item.id }}-{{ kwargs.Video_type_id }}-{{ kwargs.Video_dif_id }}">{{ item.Video_group }}</a> {% endif %} {% endfor %} </div> <div> {% if kwargs.Video_type_id == 0%} <a href="/video2-{{ kwargs.Video_group_id }}-0-{{ kwargs.Video_dif_id }}" class="active">全部</a> {% else %} <a href="/video2-{{ kwargs.Video_group_id }}-0-{{ kwargs.Video_dif_id }}">全部</a> {% endif %} {% for item in VideoType_list %} {% if item.id == kwargs.Video_type_id %} <a class="active" href="/video2-{{ kwargs.Video_group_id }}-{{ item.id }}-{{ kwargs.Video_dif_id }}">{{ item.Video_Type }}</a> {% else %} <a href="/video2-{{ kwargs.Video_group_id }}-{{ item.id }}-{{ kwargs.Video_dif_id }}">{{ item.Video_Type }}</a> {% endif %} {% endfor %} </div> <div> {% if kwargs.Video_dif_id == 0%} <a href="/video2-{{ kwargs.Video_group_id }}-{{ kwargs.Video_type_id }}-0" class="active">全部</a> {% else %} <a href="/video2-{{ kwargs.Video_group_id }}-{{ kwargs.Video_type_id }}-0">全部</a> {% endif %} {% for item in VideoDif_list %} {% if item.id == kwargs.Video_dif_id %} <a class="active" href="/video2-{{ kwargs.Video_group_id }}-{{ kwargs.Video_type_id }}-{{ item.id }}">{{ item.Video_dif }}</a> {% else %} <a href="/video2-{{ kwargs.Video_group_id }}-{{ kwargs.Video_type_id }}-{{ item.id }}">{{ item.Video_dif }}</a> {% endif %} {% endfor %} </div> </div> <div> <h1>结果</h1> <div> {% for item in video_list %} <p>{{ item.Video_title }}</p> {% endfor %} </div> </div> </body> </html>