django多条件筛选搜索(项目实例)
多条件搜索在很多网站上都有用到,比如京东,淘宝,51cto,等等好多购物教育网站上都有,当然网上也有很多开源的比楼主写的好的多了去了,仅供参考,哈哈
先来一张效果图吧,不然幻想不出来是什么样的,前端样式很low,毕竟主要是说后台的嘛,前端为了简单测试就简单的写出来啦,喜欢好的样式可以自己去调哈
写后台的应该都知道先从数据库方面入手,所以我们先来设计数据库
数据库设计
1、视频video
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
2、视频方向Direction
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
3、视频分类Classification
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
好了大家一起来分析下数据库设计
-
视频方向Direction类和视频分类Classification多对多关系,因为一个视频方向可以有多个分类,一个视频分类也可以有多个视频方向视频分类
-
Classification视频分类和视频Video类是一对多关系,因为一个分类肯定有好多视频
- 视频Video类中level_choice 与视频也是一对多关系,因为这个也就这三个分类,所以我选择把他放在内存里面取,毕竟这玩意常年不会变
url映射
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^video-(?P<direction_id>\d+)-(?P<classification_id>\d+)-(?P<level_id>\d+).html', views.video), ]
输入的url为:http://127.0.0.1:8080/video-0-0-0.html
-
中间第一个0代表视频方向,第二个0代表食品分类,第三个0是视频等级,这个是根据汽车之间那个二手车学的,用着很方便哈哈
-
0代表全部,然后递增,当选择运维自动化,第一个0就会变成1
-
下面那些都是一样的道理
前端代码
前端HTML,有用到django的simple_tag,从总体效果图可以看出,前端主要分为两部分,选择部分和视频展示部分
1、选择部分
<h3>选择:</h3> <div> {% action_all current_url 1 %} : {% for item in direction_list %} {% action current_url item %} {% endfor %} </div> <div> {% action_all current_url 2 %} : {% for item in class_list %} {% action current_url item %} {% endfor %} </div> <div> {% action_all current_url 3 %} : {% for item in level_list %} {% action current_url item %} {% endfor %} </div>
中间主要是用simple_tag来做的前端代码
@register.simple_tag def action_all(current_url,index): """ 获取当前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>" 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) temp = temp % (href,) return mark_safe(temp) @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
2、视频展示区域
<h3>视频:</h3> {% for item in video_list %} <a class="item" href="{{ item.href }}"> <img src="/{{ item.img }}" width="300px" height="400px"> <p>{{ item.title }}</p> <p>{{ item.summary }}</p> </a> {% endfor %}
关键来啦关键来啦,最主要的处理部分在这里,往这看,往这看,往这看,主要的事情说三遍哈
视频后台逻辑处理部分
def video(request,*args,**kwargs): print(kwargs) # 当前请求的路径 request_path = request.path # 从数据库获取视频时的filter条件字典 q = {} # 状态为审核通过的 q['status'] = 1 # 获取url中的视频分类id class_id = int(kwargs.get('classification_id')) # 从数据库中获取所有的视频方向(包括视频方向的id和name) direction_list = models.Direction.objects.all().values('id','name') # 如果视频方向是0 if kwargs.get('direction_id') == '0': # 方向选择全部 # 方向id=0,即获取所有的视频分类(包括视频分类的id和name) class_list = models.Classification.objects.all().values('id', 'name') # 如果视频分类id也为0,即全部分类,那就什么都不用做,因为已经全取出来了 if kwargs.get('classification_id') == '0': pass else: # 如果视频分类不是全部,过滤条件为视频分类id在[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 id_list = list(map(lambda x: x['id'], class_list)) # 过滤条件为视频分类id in [该方向下的所有视频分类id] q['classification_id__in'] = id_list 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)) # 过滤条件为视频分类id in [已经选择的视频分类id] q['classification_id__in'] = [class_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) # 视频等级id level_id = int(kwargs.get('level_id')) if level_id == 0: pass else: # 过滤条件增加视频等级 q['level'] = level_id # 取出相对应的视频 video_list = models.Video.objects.filter(**q).values('title','summary', 'img', 'href') # 把视频等级转化为单个标签是字典格式,整体是列表格式 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})