Django实现瀑布流,组合搜索
Django中组合搜索功能
需求分析
很多电商网站中有组合搜索的功能,所谓组合搜索就是网页中组合多个条件,对数据库中进行查询,并且将结果显示在页面中,看个例子吧:
注意红框中的标识,我们可以根据URL来做组合搜索.
video-3-1-1.html 使用split可以将三个数字取到,
第一位数字: 分类
第二位数字: 课程名称
第三位数字: 级别
urls.py
首先,如果想把url按我们的需求取出来,我们可以在urls.py中设置:
from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), # url(r'^student/', views.student), url(r'^video-(?P<direction_id>\d+)-(?P<classfication_id>\d+)-(?P<level_id>\d+).html', views.video), ]
说明下,这里是本身的正则表达式的语法,先分组,并且赋予了变量
1.此处的(?P<name>…),和普通的(?…): 基本类似。区别在于,此处由于是给此group命名了,所以,后续(同一正则表达式内和搜索后得到的Match对象中),都可以通过此group的名字而去引用此group。 2. group的名字,当前需要是正常的Python标识符,即字母,数字,下划线等,即,没有特殊的字符。 3.同一正则表达式内,每个group的组名,是唯一的,不能重复。 4. 虽然此处group内命名了,但是其仍然和普通的
modles.py
from django.db import models # 技术方向, class Direction(models.Model): 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 # 技术分类、语言 class Classification(models.Model): 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): level_choice = ( (1, u'初级'), (2, u'中级'), (3, u'高级'), ) level = models.IntegerField(verbose_name='级别', choices=level_choice, default=1) classification = models.ForeignKey('Classification', null=True, blank=True) 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
技术方向:多对多技术分类
技术视频:一对多技术分类
views.py
from django.shortcuts import render from app01 import models # Create your views here. def video(request,**kwargs): #在url.py中已经设置,结果为:{'direction_id': '3', 'classfication_id': '4', 'level_id': '1'} print(kwargs) print(request.path_info) #request.path._info可以得到url的后缀,比如:/video-3-4-1.html current_url = request.path_info direction_id = kwargs.get('direction_id','0') classfication_id = kwargs.get('classfication_id', '0') q = {} # 方向是0,表示是全部 if direction_id == '0': #如果技术分类id为0,取分类数据库中的数据,为字典模式,元素为id和name cList = models.Classification.objects.values('id', 'name') # 分类是0 if classfication_id == '0': # 如果课程也是全部,video-0-0 pass else: # video-0-1 # 否则,选中了对应的分类 q['classification__id'] = classfication_id else: #如果分类不是全部,得到分类对应的数据,通过map函数处理迭代器temp,并将其转化为列表,取得ID obj = models.Direction.objects.get(id=direction_id) temp = obj.classification.all().values('id','name') id_list = list(map(lambda x:x['id'],temp)) cList = obj.classification.all().values('id','name') if classfication_id == '0': # video-1-0 # 根据方向ID,找到所属的分类ID print(id_list) q['classification__id__in'] = id_list else: # video-1-1 #如果分类ID在方向ID列表中 if int(classfication_id) in id_list: q['classification__id'] = classfication_id else: q['classification__id__in'] = id_list #url分割取分类的ID,然后改为0,修改url url_list = current_url.split('-') url_list[2] = "0" current_url = '-'.join(url_list) level_id = kwargs.get('level_id',None) if level_id != '0': q['level'] = level_id result = models.Video.objects.filter(**q) dList = models.Direction.objects.values('id', 'name') lList = models.Video.level_choice # level_choice = ( # (1, u'初级'), # (2, u'中级'), # (3, u'高级'), # ) return render(request, 'video.html', {"dList":dList, 'cList': cList, 'lList': lList, 'current_url': current_url})
自定义扩展template函数
由于处理函数比较复杂,所以我们要写一些自定义的simple_tag函数,用来对相应的a标签进行href预处理,得到相应的url路径,vied_tag.py:
from django import template from django.utils.safestring import mark_safe ############################################ #此部分无用 register = template.Library() @register.simple_tag def action1(current_url, nid): # /video-2-1-3.html url_list = current_url.split('-') url_list[1] = str(nid) return '-'.join(url_list) @register.simple_tag def action2(current_url, nid): # /video-2-1-3.html url_list = current_url.split('-') url_list[2] = str(nid) return '-'.join(url_list) @register.simple_tag def action3(current_url, nid): # /video-2-1-3.html url_list = current_url.split('-') url_list[3] = str(nid) + '.html' return '-'.join(url_list) ################################################### @register.simple_tag def ac1(current_url, nid, name): # # /video-2-1-3.html url_list = current_url.split('-') old = url_list[1] if old == str(nid): temp = '<a class="active" href="%s">%s</a>' else: temp = '<a href="%s">%s</a>' url_list[1] = str(nid) tag = temp %('-'.join(url_list),name) return mark_safe(tag) @register.simple_tag def ac2(current_url, nid, name): # # /video-2-1-3.html url_list = current_url.split('-') old = url_list[2] if old == str(nid): temp = '<a class="active" href="%s">%s</a>' else: temp = '<a href="%s">%s</a>' url_list[2] = str(nid) tag = temp %('-'.join(url_list),name) return mark_safe(tag) @register.simple_tag def ac3(current_url, nid, name): # # /video-2-1-3.html url_list = current_url.split('-') old = url_list[3] if old == str(nid) + '.html': temp = '<a class="active" href="%s">%s</a>' else: temp = '<a href="%s">%s</a>' url_list[3] = str(nid) + '.html' tag = temp %('-'.join(url_list),name) return mark_safe(tag) @register.simple_tag def all_menu(current_url): # video-0-10-0.html url_list = current_url.split('-') if url_list[1] == '0': temp = '<a class="active" href="%s">全部</a>' else: temp = '<a href="%s">全部</a>' url_list[1] = '0' temp = temp %('-'.join(url_list)) return mark_safe(temp)
vedio.html
{% load vied_tag%} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> // 设定之间的间隔 .condition a{ display: inline-block; padding: 5px; } // 设定当前选择条件的css样式 .condition a.active{ background-color: coral; color: white; } </style> </head> <body> <div class="condition"> <div> // 处理全部 {% all_menu current_url %} : // 遍历方向列表 {% for i in dList %} // 将方向列表中的id,name作为参数传入定义好的自定义函数中处理,生成 {% ac1 current_url i.id i.name %} {% endfor %} </div> <div> {% for i in cList %} {% ac2 current_url i.id i.name %} {% endfor %} </div> <div> {% for i in lList %} {% ac3 current_url i.0 i.1 %} {% endfor %} </div> </div> </body> </html>
django实现图片瀑布流布局
我们在一些图片网站上经常会看到,满屏都是图片,而且图片都大小不一,却可以按空间排列。默认一个div是占用一行,当想把div里的图片并排显示的时候,只能使用float属性,但是,如果两张图片大小不一,那么第二行图片会以第一张最大的图片占用的空间为基准,进行第二行显示,这样的图片布局就非常难看,今天实现的就是瀑布流的形式
实现效果:
一般我们做图片布局的时候,都是采用div中加入img,然后将div float起来,这样图片就会并排显示。实现瀑布流的原理就是,我们换一种布局方式,首先定义好需要显示多少列图片,多少列就是多少和div,然后在每列的div中去加入div包着的图片,由于图片外的div是行标签,所以默认独占一行,所以,在本列的div中,图片就无缝的向下排列了,同理,其他列也是,这样总体布局就出现了,看下图
view.py
def student(request): img_list = [ {'src': '1.jpg', 'title': 'asdfasdfasdf','content': 'asdf'},# 1 {'src': '2.jpg', 'title': 'asdfasdfasdf','content': 'asdf'},# 2 {'src': '3.jpg', 'title': 'asdfasdfasdf','content': 'asdf'}, {'src': '4.jpg', 'title': 'asdfasdfasdf','content': 'asdf'}, {'src': '5.jpg', 'title': 'asdfasdfasdf','content': 'asdf'},# 5 {'src': '6.jpg', 'title': 'asdfasdfasdf','content': 'asdf'}, ] return render(request, 'student.html', {"img_list":img_list})
首先分析,现在以四列布局 div分别是a、b、c、d, 那么图片1就在div a中,图片2就在div b中,图片3就在div c中,图片4就在div d中,到图片5时,就继续从div a中开始,后面依次。发现,其中的规律就是第多少张图片 n 除以 4,的余数m 就是第m个div。根据这个规律,我们可以使用模版语言中自定义的方法去进行判断,如果本图片 除以4,正好等于所比较的div 号,那么就放进去
代码:
templatetags-vied_tag
from django import template register = template.Library() @register.filter def detail1(value,arg): """ 查看余数是否等于remainder arg="1,2" :param counter: :param allcount: :param remainder: :return: """ allcount, remainder = arg.split(',') allcount = int(allcount) remainder = int(remainder) if value%allcount == remainder: return True return False
html 代码
{% load vied_tag %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .container{ width: 980px; margin: 0 auto; } .container .column{ float: left; width: 245px; } .container .item img{ width: 245px; } </style> </head> <body> <div class="container"> <div class="column"> {% for i in img_list %} {% if forloop.counter|detail1:"4,1" %} <div class="item"> {{ forloop.counter }} <img src="/static/{{ i.src }}"> </div> {% endif %} {% endfor %} </div> <div class="column"> {% for i in img_list %} {% if forloop.counter|detail1:"4,2" %} <div class="item"> {{ forloop.counter }} <img src="/static/{{ i.src }}"> </div> {% endif %} {% endfor %} </div> <div class="column"> {% for i in img_list %} {% if forloop.counter|detail1:"4,3" %} <div class="item"> {{ forloop.counter }} <img src="/static/{{ i.src }}"> </div> {% endif %} {% endfor %} </div> <div class="column"> {% for i in img_list %} {% if forloop.counter|detail1:"4,0" %} <div class="item"> {{ forloop.counter }} <img src="/static/{{ i.src }}"> </div> {% endif %} {% endfor %} </div> </div> </body> </html>
上面只是简单的利用模版语言 实现了瀑布流布局,但是会发现图片列表需要循环四次,这样效率不好,一般情况下,可以使用ajax,先获取到图片列表,然后js去循环列表,然后在循环中,将当前循环的元素索引 去和4相除,拿到余数,最后使用jquery 根据余数进行直接定位到对应的
参考学习:https://www.cnblogs.com/pycode/articles/django3.html