西游之路——python全栈——组合搜索
一、一对多关系
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from django.db import models
2
3 class Direction(models.Model):
4 '''
5 方向:自动化 测试 运维 前端
6 '''
7 weight = models.IntegerField(verbose_name='权重', default=0)
8 name = models.CharField(verbose_name='名称', max_length=32, unique=True)
9 classification = models.ManyToManyField('Classification')
10 class Meta:
11 db_table = 'Direction'
12 verbose_name_plural = '方向(视频方向)'
13 def __str__(self):
14 return self.name
15
16 class Classification(models.Model):
17 '''
18 分类:python Linux JavaScript OpenStack node.js
19 '''
20 weight = models.IntegerField(verbose_name='权重', default=0)
21 name = models.CharField(verbose_name='名称', max_length=32, unique=True)
22 class Meta:
23 db_table = 'Classification'
24 verbose_name_plural = '分类(视频分类)'
25 def __str__(self):
26 return self.name
27
28 class Level(models.Model):
29 title = models.CharField(max_length=32)
30 class Meta:
31 verbose_name_plural = '难度级别'
32 def __str__(self):
33 return self.title
34
35 class Video(models.Model):
36 status_choice = (
37 (2, '上线'),
38 (1, '下线'),
39 )
40 # level_choice = (
41 # (1, '初级'),
42 # (2, '中级'),
43 # (3, '高级'),
44 # )
45 status = models.IntegerField(verbose_name='状态', choices=status_choice, default=1)
46 # level = models.IntegerField(verbose_name='级别', choices=level_choice, default=1)
47 level = models.ForeignKey('Level', null=True, blank=True,on_delete=models.CASCADE)
48
49 classification = models.ForeignKey('Classification', null=True, blank=True,on_delete=models.CASCADE)
50
51 weight = models.IntegerField(verbose_name='权重', default=0)
52
53 title = models.CharField(verbose_name='标题', max_length=32)
54 summary = models.CharField(verbose_name='简介', max_length=32)
55 img = models.ImageField(verbose_name='图片', upload_to='./static/images/Video/')
56 href = models.CharField(verbose_name='视频地址',max_length=256)
57
58 create_date = models.DateTimeField(auto_now_add=True)
59
60 class Meta:
61 db_table = 'Video'
62 verbose_name_plural = '视频'
63
64 def __str__(self):
65 return self.title
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 urlpatterns = [
2 re_path('admin/', admin.site.urls),
3 re_path('video-(?P<classification_id>(\d+))-(?P<level_id>(\d+))-(?P<status>(\d+)).html/$', views.video),
4 re_path('video2-(?P<direction_id>(\d+))-(?P<classification_id>(\d+))-(?P<level_id>(\d+)).html/$', views.video2),
5 ]
注意:
1、大写的P
2、伪造静态页面
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from django.shortcuts import render 2 from app01 import models 3 4 def video(request,*args,**kwargs): 5 condition = { 6 # 'level_id':1, 7 # 'classification_id':1 8 } 9 # 构造查询字典 10 for k,v in kwargs.items(): 11 tem = int(v) 12 kwargs[k] = tem 13 # 排除0 14 if tem: 15 condition[k] = tem 16 # 循环复制,构造列表字典,以便HTML中调用方式看起来合乎常理 17 status_list = list(map(lambda x:{'id':x[0],'name':x[1]},models.Video.status_choice)) # 普通字段提取 18 19 direction_list = models.Direction.objects.all() 20 class_list = models.Classification.objects.all() 21 level_list = models.Level.objects.all() 22 # 字典和列表加** 23 video_list = models.Video.objects.filter(**condition) 24 25 return render(request, 'video.html',locals())
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <head> 2 <meta charset="UTF-8"> 3 <title>Title</title> 4 <style> 5 .condition a{ 6 display: inline-block; 7 padding: 5px 8px; 8 border: 1px solid #dddddd; 9 } 10 .condition a.active{ 11 background-color: coral; 12 color: white; 13 } 14 </style> 15 </head> 16 <body> 17 <div class="condition"> 18 <h1>筛选</h1> 19 <div> 20 {# 高亮显示选中 #} 21 {% if kwargs.classification_id == 0 %} 22 <a class="active" href="/video-0-{{kwargs.level_id}}-{{kwargs.status}}.html">全部</a> 23 {% else %} 24 <a href="/video-0-{{kwargs.level_id}}-{{kwargs.status}}.html">全部</a> 25 {% endif %} 26 {% for item in class_list %} 27 {% if item.id == kwargs.classification_id %} 28 <a class="active" href="/video-{{item.id}}-{{kwargs.level_id}}-{{kwargs.status}}.html">{{item.name}}</a> 29 {% else %} 30 <a href="/video-{{item.id}}-{{kwargs.level_id}}-{{kwargs.status}}.html">{{item.name}}</a> 31 {% endif %} 32 {% endfor %} 33 </div> 34 <div> 35 {% if kwargs.level_id == 0 %} 36 <a class="active" href="/video-{{kwargs.classification_id}}-0-{{kwargs.status}}.html">全部</a> 37 {% else %} 38 <a href="/video-{{kwargs.classification_id}}-0-{{kwargs.status}}.html">全部</a> 39 {% endif %} 40 {% for item in level_list %} 41 {% if item.id == kwargs.level_id %} 42 <a class="active" href="/video-{{kwargs.classification_id}}-{{item.id}}-{{kwargs.status}}.html">{{item.title}}</a> 43 {% else %} 44 <a href="/video-{{kwargs.classification_id}}-{{item.id}}-{{kwargs.status}}.html">{{item.title}}</a> 45 {% endif %} 46 {% endfor %} 47 </div> 48 <div> 49 {% if kwargs.status == 0 %} 50 <a class="active" href="/video-{{kwargs.classification_id}}-{{kwargs.level_id}}-0.html">全部</a> 51 {% else %} 52 <a href="/video-{{kwargs.classification_id}}-{{kwargs.level_id}}-0.html">全部</a> 53 {% endif %} 54 {% for item in status_list %} 55 {% if item.id == kwargs.status %} 56 <a class="active" href="/video-{{kwargs.classification_id}}-{{kwargs.level_id}}-{{item.id}}.html">{{item.name}}</a> 57 {% else %} 58 <a href="/video-{{kwargs.classification_id}}-{{kwargs.level_id}}-{{item.id}}.html">{{item.name}}</a> 59 {% endif %} 60 {% endfor %} 61 </div> 62 </div> 63 <h1>结果</h1> 64 <div> 65 {% for row in video_list %} 66 <div>{{row.title}}</div> 67 <div>{{row.summary}}</div> 68 <div>{{row.img}}</div> 69 {% endfor %} 70 </div> 71 </body>
1、筛选条件间互不影响
2、发送URL请求时,只是选中ID变化,其他保持不变
二、多对多
1、数据库表设计和URL见上
2、
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def video2(request, *args, **kwargs):
2 # 构造查询字典
3 for k,v in kwargs.items():
4 kwargs[k] = int(v)
5 # 提取出各自ID
6 direction_id = kwargs.get('direction_id')
7 classification_id = kwargs.get('classification_id')
8 level_id = kwargs.get('level_id')
9
10 # 把对Video的筛选条件存入condition字典中
11 condition = {}
12 if direction_id == 0:
13 class_list = models.Classification.objects.all()
14 if classification_id == 0:
15 pass
16 else:
17 condition['classification_id'] = classification_id
18 else:
19 direction_obj = models.Direction.objects.filter(id=direction_id).first()
20 class_list = direction_obj.classification.all()
21
22 vlist = direction_obj.classification.all().values_list('id')
23 # 判断方向无分类情况
24 if not vlist:
25 classification_id_list = []
26 else:
27 # v=[(1,2.3),(4,5.6)] => list(zip(*v)) => [(1, 4), (2, 5), (3, 6)]
28 # list(zip(*v))[0] => (1,4)
29 classification_id_list = list(zip(*vlist))[0] ######
30 if classification_id == 0:
31 condition['classification_id__in'] = classification_id_list
32 else:
33 if classification_id in classification_id_list:
34 condition['classification_id'] = classification_id
35 else:
36 # 切换方向时,选中的分类不在此方向中则清零(跳转到全部)
37 kwargs['classification_id'] = 0 ######
38 condition['classification_id__in'] = classification_id_list
39
40 # 加入level对video的筛选条件
41 if level_id == 0:
42 pass
43 else:
44 condition['level_id'] = level_id
45
46 direction_list = models.Direction.objects.all()
47 level_list = models.Level.objects.all()
48 video_list = models.Video.objects.filter(**condition).all()
49
50 return render(request,'video2.html',locals())
注意:条件之间是有关联,先理清条件之间的关系,然后是条件跟结果的关系
3、
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>Title</title>
6 <style>
7 .condition a{
8 display: inline-block;
9 padding: 5px 8px;
10 border: 1px solid #dddddd;
11 }
12 .condition a.active{
13 background-color: coral;
14 color: white;
15 }
16 </style>
17 </head>
18 <body>
19 <div class="condition">
20 <h1>筛选</h1>
21 <div>
22 {% if kwargs.direction_id == 0 %}
23 <a class="active" href="/video2-0-{{kwargs.classification_id}}-{{kwargs.level_id}}.html">全部</a>
24 {% else %}
25 <a href="/video2-0-{{kwargs.classification_id}}-{{kwargs.level_id}}.html">全部</a>
26 {% endif %}
27 {% for item in direction_list %}
28 {% if item.id == kwargs.direction_id %}
29 <a class="active" href="/video2-{{item.id}}-{{kwargs.classification_id}}-{{kwargs.level_id}}.html">{{item.name}}</a>
30 {% else %}
31 <a href="/video2-{{item.id}}-{{kwargs.classification_id}}-{{kwargs.level_id}}.html">{{item.name}}</a>
32 {% endif %}
33 {% endfor %}
34 </div>
35 <div>
36 {% if kwargs.classification_id == 0 %}
37 <a class="active" href="/video2-{{kwargs.direction_id}}-0-{{kwargs.level_id}}.html">全部</a>
38 {% else %}
39 <a href="/video2-{{kwargs.direction_id}}-0-{{kwargs.level_id}}.html">全部</a>
40 {% endif %}
41 {% for item in class_list %}
42 {% if item.id == kwargs.classification_id %}
43 <a class="active" href="/video2-{{kwargs.direction_id}}-{{item.id}}-{{kwargs.level_id}}.html">{{item.name}}</a>
44 {% else %}
45 <a href="/video2-{{kwargs.direction_id}}-{{item.id}}-{{kwargs.level_id}}.html">{{item.name}}</a>
46 {% endif %}
47 {% endfor %}
48 </div>
49 <div>
50 {% if kwargs.level_id == 0 %}
51 <a class="active" href="/video2-{{kwargs.direction_id}}-{{kwargs.classification_id}}-0.html">全部</a>
52 {% else %}
53 <a href="/video2-{{kwargs.direction_id}}-{{kwargs.classification_id}}-0.html">全部</a>
54 {% endif %}
55 {% for item in level_list %}
56 {% if item.id == kwargs.level_id %}
57 <a class="active" href="/video2-{{kwargs.direction_id}}-{{kwargs.classification_id}}-{{item.id}}.html">{{item.title}}</a>
58 {% else %}
59 <a href="/video2-{{kwargs.direction_id}}-{{kwargs.classification_id}}-{{item.id}}.html">{{item.title}}</a>
60 {% endif %}
61 {% endfor %}
62 </div>
63 </div>
64 <h1>结果</h1>
65 <div>
66 {% for item in video_list %}
67 <a href="">{{item.title}}</a>
68 {% endfor %}
69 </div>
70
71 </body>
72 </html>