一、瀑布流,是指页面布局中,在显示很多图片时,图片及文字大小不相同,导致页面排版不美观
如上图,右边的布局,因为第一行第一张图片过长,第二行的第一张被挤到第二列了。示例:
def flow(request):
user_list = [
{'name': '张1三', 'src': '/static/image/1.jpg', 'company': '特事特办中国特色一公司','summary': '一群老油条烦死打法撒飞洒的飞洒烦死哒防守打法噶三群老油条烦死哒范德萨分散发士大夫士大夫是打发发防守打法烦死哒防守打法噶第三方三'},
{'name': '张2三', 'src': '/static/image/1.jpg', 'company': '特事特办中国特色一公司','summary': '一群老油'},
{'name': '张3三', 'src': '/static/image/1.jpg', 'company': '特事特办中国特色一公司','summary': '一群老油条烦分打发发防守打法撒飞洒的飞洒烦死哒防守打法噶第三'},
{'name': '张4三', 'src': '/static/image/1.jpg', 'company': '特事特办中国特色一公司','summary': '一群老油条烦死哒范德萨分散发士大夫士大夫是打发发防守打法烦死哒防守打法噶第三方三'},
{'name': '张5三', 'src': '/static/image/1.jpg', 'company': '特事特办中国特色一公司','summary': '一群老油条烦死哒范德萨分散发士大夫士大夫是打发发防守打法'},
{'name': '张6三', 'src': '/static/image/1.jpg', 'company': '特事特办中国特色一公司','summary': '一群老油条烦死哒范洒的飞洒烦死哒防守打法噶第三方三'},
{'name': '张7三', 'src': '/static/image/1.jpg', 'company': '特事特办中国特色一公司','summary': '一群老油条烦死哒范德萨分散发士大夫士大夫是打发发防守打噶第三方三'},
{'name': '张8三', 'src': '/static/image/1.jpg', 'company': '特事特办中国特色一公司','summary': '一法撒飞洒的飞洒烦死哒防守打法噶第三方三'},
]
return render(request,"flow.html",{'user_list':user_list})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.container{
width: 900px;
margin: 0 auto;
}
.container .item{
width: 300px;
float: left;
}
.container .item img{
width: 200px;
height: 180px;
}
.container .item p{
padding-left: 10px;
padding-right: 40px;
}
</style>
</head>
<body>
<div class="container">
{% for row in user_list %}
<div class="item">
<img src="{{ row.src }}">
<p>{{ row.name }}</p>
<p>{{ row.summary }}</p>
</div>
{% endfor %}
</div>
</body>
</html>
此时显示如下:
很不美观,解决方法,是先将页面分为三个div,让后让图片依次在三个div中排放。
纯静态HTML实现:
<div class="container">
<div style="width: 900px;margin: 0 auto;">
<div style="width: 280px;float: left;">
<div class="item">
<img src="{{ user_list.0.src }}">
<p>{{ user_list.0.name }}1</p>
<p>{{ user_list.0.summary }}<br>fdsafdsafd<br>safsdafsd<br>afsdaff<br>assdf</p>
</div>
<div class="item">
<img src="{{ user_list.0.src }}">
<p>{{ user_list.0.name }}4</p>
<p>{{ user_list.0.summary }}<br>fdsafdsafd<br>safsdafsd<br>afsdaff<br>assdf</p>
</div>
</div>
<div style="width: 280px;float: left;">
<div class="item">
<img src="{{ user_list.0.src }}">
<p>{{ user_list.0.name }}2</p>
<p>{{ user_list.0.summary }}</p>
</div>
<div class="item">
<img src="{{ user_list.0.src }}">
<p>{{ user_list.0.name }}5</p>
<p>{{ user_list.0.summary }}<br>fdsafdsafd<br>safsdafsd<br>afsdaff<br>assdf</p>
</div>
</div>
<div style="width: 280px;float: left;">
<div class="item">
<img src="{{ user_list.0.src }}">
<p>{{ user_list.0.name }}3</p>
<p>{{ user_list.0.summary }}</p>
</div>
</div>
</div>
</div>
这就实现了瀑布流,使用模板渲染:最初想法如下
<div style="width: 900px;margin: 0 auto;">
{% for row in user_list %}
<div style="width: 300px;float: left;">
{% if forloop.counter%3 == 1 %} {# 这里出错 #}
<div class="item">
<img src="{{ row.src }}">
<p>{{ row.name }}</p>
<p>{{ row.summary }}</p>
</div>
{% endif %}
</div>
<div style="width: 300px;float: left;">
{% if forloop.counter%3 == 2 %} {# 这里出错 #}
<div class="item">
<img src="{{ row.src }}">
<p>{{ row.name }}</p>
<p>{{ row.summary }}</p>
</div>
{% endif %}
</div>
<div style="width: 300px;float: left;">
{% if forloop.counter%3 == 0 %} {# 这里出错 #}
<div class="item">
<img src="{{ row.src }}">
<p>{{ row.name }}</p>
<p>{{ row.summary }}</p>
</div>
{% endif %}
</div>
{% endfor %}
</div>
取模操作%无法在模板中使用,因为使用到了if语句,自定义标签不能用在模板if语句中,所以只能考虑使用过滤器filter:
<div class="container">
<div style="width: 300px;float: left">
{% for row in user_list %}
{% if forloop.counter|mymod:'3,1' %}
<div class="item">
<img src="{{ row.src }}">
<p>{{ row.name }}{{ forloop.counter }}</p>
<p>{{ row.summary }}</p>
</div>
{% endif %}
{% endfor %}
</div>
<div style="width: 300px;float: left;">
{% for row in user_list %}
{% if forloop.counter|mymod:'3,2' %}
<div class="item">
<img src="{{ row.src }}">
<p>{{ row.name }}{{ forloop.counter }}</p>
<p>{{ row.summary }}</p>
</div>
{% endif %}
{% endfor %}
</div>
<div style="width: 300px;float: left;">
{% for row in user_list %}
{% if forloop.counter|mymod:'3,0' %}
<div class="item">
<img src="{{ row.src }}">
<p>{{ row.name }}{{ forloop.counter }}</p>
<p>{{ row.summary }}</p>
</div>
{% endif %}
{% endfor %}
</div>
</div>
# 过滤器
from django import template
register = template.Library()
@register.filter
def mymod(v1,v2):
n1,n2 = v2.split(',')
if v1%int(n1) == int(n2):
return True
return False
以上是模板渲染,使用了多次的循环,效率不是很好。
使用JS实现,使用Ajax发送一个请求,得到数据,然后在js中进行余数的判断和前端的生成。
二、组合搜索/组合筛选
简单的组合搜索如下图:
建立相应的model:
from django.db import models
# Create your models here.
class Level(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name
class Category(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name
class Video(models.Model):
lv = models.ForeignKey(Level,on_delete=models.DO_NOTHING)
cg = models.ForeignKey(Category,on_delete=models.DO_NOTHING)
title = models.CharField(verbose_name="标题",max_length=64)
summary = models.CharField(verbose_name="简介",max_length=128)
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)
创建路由项,这里查询的条件组合在路由项中,如下:
path('video-<int:cg_id>-<int:lv_id>.html',views.video,name='video_alais'),
cg_id代表种类的id,lv_id代表级别的id
对应的视图函数:
def video(req,*args,**kwargs):
condition = {}
for k,v in kwargs.items():
if v != 0:
condition[k] = v
print(condition)
category_list = models.Category.objects.all()
level_list = models.Level.objects.all()
result = models.Video.objects.filter(**condition)
return render(req,'video.html',{
'category_list':category_list,
'level_list':level_list,
'result':result,
'arg_dict':kwargs,
})
前端模板文件video.html:
{% load tagandfilter %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.filter a {
display: inline-block;
margin: 5px;
padding: 3px 5px;
}
.filter a.active{
background-color: brown;
color: white;
}
</style>
</head>
<body>
<h1>筛选条件</h1>
<div class="filter">
<div>
{% total_tag arg_dict "cg_id" %}:
{% for item in category_list %}
{% categroy_tag item arg_dict %}
{% endfor %}
</div>
<div>
{% total_tag arg_dict "lv_id" %}:
{% for item in level_list %}
{% level_tag item arg_dict %}
{% endfor %}
</div>
</div>
<h1>查询结果</h1>
<div class="content">
{% for item in result %}
<div style="width:180px;height:200px;float: left">
<img width="150px" height="200px" src="{{ item.img }}">
<p>{{ item.title }}</p>
<p>{{ item.summary }}</p>
<p>{{ item.create_date }}</p>
</div>
{% endfor %}
</div>
</body>
</html>
模板中使用了自定义标签:
@register.simple_tag
def categroy_tag(obj,arg_dict):
'''
生成种类的A标签
:param obj:
:param arg_dict:
:return:
'''
url = reverse("video_alais",kwargs={'cg_id':obj.id,'lv_id':arg_dict.get('lv_id')})
if obj.id == arg_dict.get('cg_id'):
tag = "<a class='active' href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
else:
tag = "<a href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
@register.simple_tag
def level_tag(obj,arg_dict):
'''
生成级别的A标签
:param obj:
:param arg_dict:
:return:
'''
url = reverse("video_alais", kwargs={'lv_id': obj.id, 'cg_id': arg_dict.get('cg_id')})
if obj.id == arg_dict.get('lv_id'):
tag = "<a class='active' href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
else:
tag = "<a href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
@register.simple_tag
def total_tag(arg_dict,key):
if key == 'cg_id':
url = reverse("video_alais", kwargs={'cg_id': 0, 'lv_id': arg_dict.get('lv_id')})
elif key == 'lv_id':
url = reverse("video_alais", kwargs={'lv_id': 0, 'cg_id': arg_dict.get('cg_id')})
else:
url = ""
tag = "<a href='%s'>全部:</a>" %(url)
return mark_safe(tag)
增加一个关联表:Direction,与种类表形成多对多关系:
class Direction(models.Model):
name = models.CharField(max_length=32)
d_2_c = models.ManyToManyField("Category")
使分类根据方向动态变化:大体如下
因为多了一个方向的选择项,路由项修改如下:
path('video2-<int:dr_id>-<int:cg_id>-<int:lv_id>.html',views.video2,name='video_alais2'),
视图函数views.video2:
def video2(req,*args,**kwargs):
condition = {}
dr_id = kwargs.get('dr_id')
cg_id = kwargs.get('cg_id')
lv_id = kwargs.get("lv_id")
# 可能的请求:
# 0-0-0.html 方向、分类、级别都是全部
# 1-0-0.html 方向选择了1,分类、级别是全部,此时分类应该根据方向列出有哪些分类
# 1-2-0.HTML 方向选择了1,分类选择了2,级别全部;分类先要根据方向列出可能的分类,在根据分类选择video
# 还有一种可能,方向选择了1,而1方向对应的分类没有2,此时应该处理成分类为全部,即0
direction_list = models.Direction.objects. all()
level_list = models.Level.objects.all()
if dr_id == 0:
# 未选择方向
category_list = models.Category.objects.all()
if cg_id == 0:
pass # 未选择分类 - 未选择方向
else:
# 选择了分类 - 未选择方向
models.Video.objects.filter(cg_id = cg_id)
condition['cg_id'] = cg_id
else:
# 选择了方向,将方向对应的分类项查询出来,对象的集合,是QuerySet
category_list = models.Category.objects.filter(direction=dr_id)
# 选取其中的id字段对象集合
v = category_list.values_list('id')
# print(v.query) # 打印出查询的SQL语句
cg_id_list = list(zip(*v))[0] # id字段集合形成元组,即(1,2,3)的样子
if cg_id == 0:
# 未选择分类 - 选择了方向
# 这种情况下,选择的条件就是选择全部分类id在cg_id_list元组中的所有video
# 即在此方向下的所有分类都要查询出来
condition['cg_id__in'] = cg_id_list
else:
# 选择了分类,并且分类在cg_id_list中
if cg_id in cg_id_list:
condition['cg_id'] = cg_id
else: # 选择了分类,并且分类不在cg_id_list中,这时就选择全部cg_id_list的全部
condition['cg_id__in'] = cg_id_list
kwargs['cg_id'] = 0
if lv_id != 0: # 级别是单独的
condition['lv_id'] = lv_id
result = models.Video.objects.filter(**condition) # 根据条件最终查询的video结果集合
return render(req,'video2.html',{
'direction_list':direction_list,
'category_list':category_list,
'level_list':level_list,
'result':result,
'arg_dict':kwargs,
})
前端模板video2.html
{% load tagandfilter %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.filter a {
display: inline-block;
margin: 5px;
padding: 3px 5px;
}
.filter a.active{
background-color: brown;
color: white;
}
</style>
</head>
<body>
<h1>筛选条件</h1>
<div class="filter">
<div>
{% total_tag_2 arg_dict "dr_id" %}
{% for item in direction_list %}
<!-- if kwargs.dr_id = item.id
加入样式
else:
没有样式
-->
{% dr_tag item arg_dict %}
{% endfor %}
</div>
<div>
{% total_tag_2 arg_dict "cg_id" %}
{% for item in category_list %}
{% cg_tag item arg_dict %}
{% endfor %}
</div>
<div>
{% total_tag_2 arg_dict "lv_id" %}
{% for item in level_list %}
{% lv_tag item arg_dict %}
{% endfor %}
</div>
</div>
<h1>查询结果</h1>
<div class="content">
{% for item in result %}
<div style="width:180px;height:200px;float: left">
<img width="150px" height="200px" src="{{ item.img }}">
<p>{{ item.title }}</p>
<p>{{ item.summary }}</p>
<p>{{ item.create_date }}</p>
</div>
{% endfor %}
</div>
</body>
</html>
自定义的标签:
@register.simple_tag
def dr_tag(obj,arg_dict):
'''
生成A标签
:param obj:
:param arg_dict:
:return:
'''
url = reverse('video_alais2',kwargs={'dr_id':obj.id,'cg_id':arg_dict.get('cg_id'),'lv_id':arg_dict.get('lv_id')})
if obj.id == arg_dict.get('dr_id'):
tag = "<a class='active' href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
else:
tag = "<a href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
@register.simple_tag
def cg_tag(obj,arg_dict):
'''
生成A标签
:param obj:
:param arg_dict:
:return:
'''
url = reverse('video_alais2',kwargs={'dr_id':arg_dict.get('dr_id'),'cg_id':obj.id,'lv_id':arg_dict.get('lv_id')})
if obj.id == arg_dict.get('cg_id'):
tag = "<a class='active' href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
else:
tag = "<a href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
@register.simple_tag
def lv_tag(obj,arg_dict):
'''
生成A标签
:param obj:
:param arg_dict:
:return:
'''
url = reverse('video_alais2',kwargs={'dr_id':arg_dict.get('dr_id'),'cg_id':arg_dict.get('cg_id'),'lv_id':obj.id})
if obj.id == arg_dict.get('lv_id'):
tag = "<a class='active' href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
else:
tag = "<a href='%s'>%s</a>" %(url,obj.name)
return mark_safe(tag)
@register.simple_tag
def total_tag_2(arg_dict,key):
if key == 'dr_id':
url = reverse("video_alais2", kwargs={'dr_id':0,'cg_id': arg_dict.get('cg_id'), 'lv_id': arg_dict.get('lv_id')})
elif key == 'cg_id':
url = reverse("video_alais2", kwargs={'dr_id': arg_dict.get('dr_id'), 'cg_id': 0, 'lv_id': arg_dict.get('lv_id')})
elif key == 'lv_id':
url = reverse("video_alais2", kwargs={'dr_id':arg_dict.get('dr_id'),'lv_id': 0, 'cg_id': arg_dict.get('cg_id')})
else:
url = ""
if arg_dict.get(key) == 0:
tag = "<a class='active' href='%s'>全部:</a>" %(url,)
else:
tag = "<a href='%s'>全部:</a>" % (url,)
return mark_safe(tag)
主要的环节是逻辑上根据方向、分类、级别的选择,动态显示各个项,然后在综合条件下选择出video。