Django多条件筛选查询
主模型只存在外键一对多关系
模型设计
# 快捷筛选状态
class Status(models.Model):
order_number = models.PositiveIntegerField(unique=True, verbose_name='状态编号')
status_tag = models.CharField(max_length=10, verbose_name='状态名称')
class Meta:
ordering = ['order_number', ]
verbose_name = '事件选择'
verbose_name_plural = verbose_name
def __str__(self):
return self.status_tag
# 项目分类
class Project(models.Model):
project_name = models.CharField(max_length=10, verbose_name='项目名称')
class Meta:
ordering = ['project_name']
verbose_name = '项目分类'
verbose_name_plural = verbose_name
def __str__(self):
return self.project_name
# 事件分类
class Category(models.Model):
category_name = models.CharField(max_length=10, verbose_name='分类名称')
class Meta:
ordering = ['category_name', ]
verbose_name = '事件分类'
verbose_name_plural = verbose_name
def __str__(self):
return self.category_name
# 事件级别
class Level(models.Model):
order_number = models.PositiveIntegerField(unique=True, verbose_name='级别编号')
level_tag = models.CharField(max_length=10, verbose_name='级别名称')
class Meta:
ordering = ['order_number', ]
verbose_name = '事件级别'
verbose_name_plural = verbose_name
def __str__(self):
return self.level_tag
# 事件内容
class EventContent(models.Model):
title = models.CharField(max_length=50, verbose_name='事件标题')
content = models.TextField(verbose_name='事件正文')
image = models.ImageField(upload_to='images/%Y/%m', blank=True, null=True, verbose_name='描述图片')
created = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated = models.DateTimeField(auto_now=True, verbose_name='更新时间')
status = models.ForeignKey(Status, on_delete=models.SET_NULL, null=True, blank=True, related_name='event_content', verbose_name='事件状态')
project = models.ForeignKey(Project, on_delete=models.SET_NULL, null=True, blank=True, related_name='event_content', verbose_name='项目分类')
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='event_content', verbose_name='事件分类')
level = models.ForeignKey(Level, on_delete=models.SET_NULL, null=True, blank=True, related_name='event_content', verbose_name='事件级别')
user = models.ForeignKey(User, related_name='event_content', verbose_name='创建人')
start_time = models.DateTimeField(default=timezone.now, verbose_name='事件开始时间')
end_time = models.DateTimeField(default=timezone.now, verbose_name='事件结束时间')
pause_time = models.DateTimeField(default=timezone.now, verbose_name='事件暂停时间')
class Meta:
ordering = ['-created']
verbose_name = '事件内容'
verbose_name_plural = verbose_name
def time_interval(self):
time_diff = (self.end_time-timezone.now())
days = time_diff.days
seconds = time_diff.seconds
minutes = seconds // 60 # 得到这些秒换算的分钟整数
second = seconds % 60 # 得到除去分钟后剩余的秒数
hours = minutes // 60
minute = minutes % 60
if self.status.order_number == 6:
return '事件已关闭!'
if days <&#61; -1:
return &#39;处理已超时&#xff01;&#39;
return &#39;{}天{}时{}分&#39;.format(days, hours, minute)
def __str__(self):
return self.title
def get_content_as_markdown(self):
"""
当使用Mardown功能时&#xff0c;我们需要先让它转义一下特殊字符&#xff0c;然后再解析出Markdown标签。
这样做之后&#xff0c;输出字符串可以安全的在模板中使用。
:return:
"""
return mark_safe(markdown(self.content, safe_mode&#61;&#39;escape&#39;))
路由设计
url(r&#39;^event/$&#39;, event, name&#61;&#39;event&#39;),
url(r&#39;^event-(?P\d&#43;)-(?P\d&#43;)-(?P\d&#43;)-(?P\d&#43;)-(?P\d&#43;).html$&#39;, event, name&#61;&#39;event_filter&#39;),
视图设计
该视图只需要查看kwargs有值的情况
def get_group_url_list(url):
"""
将访问的url存储在列表中&#xff0c;用于前端判断
EVENT_MENU_GROUP : 事件菜单组
OTHER_MENU_GROUP : 其他菜单组
:param url:
:return:
"""
group_url_list &#61; list()
group_url_list.append(url)
return group_url_list
# 显示事件列表
def event(request, **kwargs):
print(&#39;视图**kwargs的值&#xff1a;&#39;, kwargs)
if not kwargs:
# 原来的事件列表和post筛选
# events &#61; EventContent.objects.all()
queryset &#61; EventContent.objects.all()
if request.method &#61;&#61; &#39;POST&#39;:
visit_url &#61; reverse(&#39;event&#39;)
event_url_list &#61; get_group_url_list(visit_url)
filter_event_form &#61; FilterEventForm(request.POST)
if filter_event_form.is_valid():
print(&#39;表单验证通过&#39;)
user &#61; filter_event_form.cleaned_data[&#39;user&#39;]
status &#61; filter_event_form.cleaned_data[&#39;status&#39;]
project &#61; filter_event_form.cleaned_data[&#39;project&#39;]
category &#61; filter_event_form.cleaned_data[&#39;category&#39;]
level &#61; filter_event_form.cleaned_data[&#39;level&#39;]
queryset &#61; queryset.filter(user&#61;user, status&#61;status, project&#61;project, category&#61;category, level&#61;level)
print(queryset)
else:
visit_url &#61; reverse(&#39;event&#39;)
event_url_list &#61; get_group_url_list(visit_url)
filter_event_form &#61; FilterEventForm()
page &#61; request.GET.get(&#39;page&#39;, 1)
paginator &#61; Paginator(queryset, settings.PAGE_NUM) # paginator是分页对象
try:
events &#61; paginator.page(page)
except PageNotAnInteger:
events &#61; paginator.page(1)
except EmptyPage:
events &#61; paginator.page(paginator.num_pages)
return render(request, &#39;event.html&#39;,
{
&#39;events&#39;: events,
&#39;EVENT_MENU_GROUP&#39;: event_url_list,
&#39;filter_event_form&#39;: filter_event_form,
&#39;old_filter&#39;: True
})
else:
"""
多条件事件筛选
event-(?P\d&#43;)-(?P\d&#43;)-(?P\d&#43;)-(?P\d&#43;)-(?P\d&#43;).html
{&#39;user_id&#39;: &#39;0&#39;, &#39;status_id&#39;: &#39;0&#39;, &#39;level_id&#39;: &#39;0&#39;, &#39;category_id&#39;: &#39;0&#39;, &#39;project_id&#39;: &#39;0&#39;}
"""
filter_dict &#61; dict()
request_path &#61; request.path
print(&#39;请求地址&#xff1a;&#39;, request_path)
if kwargs[&#39;user_id&#39;] !&#61; &#39;0&#39;:
filter_dict[&#39;user&#39;] &#61; get_object_or_404(User, id&#61;kwargs[&#39;user_id&#39;])
if kwargs[&#39;status_id&#39;] !&#61; &#39;0&#39;:
filter_dict[&#39;status&#39;] &#61; get_object_or_404(Status, id&#61;kwargs[&#39;status_id&#39;])
if kwargs[&#39;level_id&#39;] !&#61; &#39;0&#39;:
filter_dict[&#39;level&#39;] &#61; get_object_or_404(Level, id&#61;kwargs[&#39;level_id&#39;])
if kwargs[&#39;category_id&#39;] !&#61; &#39;0&#39;:
filter_dict[&#39;category&#39;] &#61; get_object_or_404(Category, id&#61;kwargs[&#39;category_id&#39;])
if kwargs[&#39;project_id&#39;] !&#61; &#39;0&#39;:
filter_dict[&#39;project&#39;] &#61; get_object_or_404(Project, id&#61;kwargs[&#39;project_id&#39;])
user_list &#61; User.objects.all().values(&#39;id&#39;, &#39;username&#39;)
# print(user_list)
status_list &#61; Status.objects.all().values(&#39;id&#39;, &#39;status_tag&#39;)
# print(status_list)
level_list &#61; Level.objects.all().values(&#39;id&#39;, &#39;level_tag&#39;)
category_list &#61; Category.objects.all().values(&#39;id&#39;, &#39;category_name&#39;)
project_list &#61; Project.objects.all().values(&#39;id&#39;, &#39;project_name&#39;)
url_id_list &#61; kwargs.values() # url中所有id&#xff1a;[0, 0, 0, 0, 0 ]
visit_url &#61; reverse(&#39;event_filter&#39;, args&#61;url_id_list)
event_url_list &#61; get_group_url_list(visit_url)
queryset &#61; EventContent.objects.filter(**filter_dict)
page &#61; request.GET.get(&#39;page&#39;, 1)
paginator &#61; Paginator(queryset, settings.PAGE_NUM) # paginator是分页对象
try:
events &#61; paginator.page(page)
except PageNotAnInteger:
events &#61; paginator.page(1)
except EmptyPage:
events &#61; paginator.page(paginator.num_pages)
return render(request, &#39;event.html&#39;,
{
&#39;events&#39;: events,
&#39;EVENT_MENU_GROUP&#39;: event_url_list,
&#39;user_list&#39;: user_list,
&#39;status_list&#39;: status_list,
&#39;level_list&#39;: level_list,
&#39;category_list&#39;: category_list,
&#39;project_list&#39;: project_list,
})
模板设计
{% if old_filter %}
{% else %}
{% active_all request.path 1 %}
{% for user_item in user_list %}
{% active request.path user_item 1 %}
{% endfor %}
{% active_all request.path 2 %}
{% for status_item in status_list %}
{% active request.path status_item 2 %}
{% endfor %}
{% active_all request.path 3 %}
{% for level_item in level_list %}
{% active request.path level_item 3 %}
{% endfor %}
{% active_all request.path 4 %}
{% for category_item in category_list %}
{% active request.path category_item 4 %}
{% endfor %}
{% active_all request.path 5 %}
{% for project_item in project_list %}
{% active request.path project_item 5 %}
{% endfor %}
{% endif %}
链接生成模板标签
使用模板标签&#xff0c;在应用下创建templatetags的python包&#xff0c;然后创建active.py文件&#xff0c;需要在模板中通过{% load active %}引入模板标签。
from django.utils.safestring import mark_safe
from django import template
register &#61; template.Library()
&#64;register.simple_tag
def active_all(request_path, index):
url_part_list &#61; request_path.split(&#39;-&#39;)
# print(url_part_list)
# [&#39;/event&#39;, &#39;0&#39;, &#39;0&#39;, &#39;0&#39;, &#39;0&#39;, &#39;0.html&#39;]
# 第五组带.html&#xff0c;需要分开判断
if url_part_list[index] &#61;&#61; &#39;0&#39; or url_part_list[index] &#61;&#61; &#39;0.html&#39;:
temp &#61; &#39;&#39;&#39;
全部
&#39;&#39;&#39;
else:
temp &#61; &#39;&#39;&#39;
全部
&#39;&#39;&#39;
if index !&#61; 5:
url_part_list[index] &#61; &#39;0&#39;
else:
url_part_list[index] &#61; &#39;0.html&#39;
href &#61; &#39;-&#39;.join(url_part_list)
return mark_safe(temp.format(href&#61;href))
&#64;register.simple_tag
def active(request_path, item, index):
url_part_list &#61; request_path.split(&#39;-&#39;)
# 下面判断中&#xff0c;前面表示 event-0-1-5-1-&#xff0c;后面表示 3.html
if url_part_list[index] &#61;&#61; str(item[&#39;id&#39;]) or url_part_list[index] &#61;&#61; str(item[&#39;id&#39;]) &#43; &#39;.html&#39;:
temp &#61; &#39;&#39;&#39;
{name}
&#39;&#39;&#39;
else:
temp &#61; &#39;&#39;&#39;
{name}
&#39;&#39;&#39;
if index &#61;&#61; 5:
# 第五组有后缀.html&#xff0c;需单独处理
url_part_list[index] &#61; str(item[&#39;id&#39;]) &#43; &#39;.html&#39;
else:
url_part_list[index] &#61; str(item[&#39;id&#39;])
href &#61; &#39;-&#39;.join(url_part_list)
if index &#61;&#61; 1:
"""
event-1-0-0-0-0.html
event-2-0-0-0-0.html
event-3-0-0-0-0.html
"""
return mark_safe(temp.format(href&#61;href, name&#61;item[&#39;username&#39;]))
if index &#61;&#61; 2:
return mark_safe(temp.format(href&#61;href, name&#61;item[&#39;status_tag&#39;]))
if index &#61;&#61; 3:
return mark_safe(temp.format(href&#61;href, name&#61;item[&#39;level_tag&#39;]))
if index &#61;&#61; 4:
return mark_safe(temp.format(href&#61;href, name&#61;item[&#39;category_name&#39;]))
if index &#61;&#61; 5:
return mark_safe(temp.format(href&#61;href, name&#61;item[&#39;project_name&#39;]))
两级分类筛选
模型设计
from django.db import models
from django.utils.timezone import now
class GoodsTag(models.Model):
name &#61; models.CharField(max_length&#61;64, verbose_name&#61;&#39;标签名称&#39;)
def __str__(self):
return self.name
class Meta:
ordering &#61; [&#39;name&#39;, ]
verbose_name &#61; &#39;商品标签&#39; # 后台显示模型名称
verbose_name_plural &#61; verbose_name
# 智能家居、手机、电视、电脑
class FirstCategory(models.Model):
name &#61; models.CharField(max_length&#61;64, verbose_name&#61;&#39;分类名称&#39;)
def __str__(self):
return self.name
class Meta:
ordering &#61; [&#39;name&#39;, ]
verbose_name &#61; &#39;一级分类&#39;
verbose_name_plural &#61; verbose_name
# 小米6、小米8、红米10
class SubCategory(models.Model):
name &#61; models.CharField(max_length&#61;64, verbose_name&#61;&#39;分类名称&#39;)
first_category &#61; models.ForeignKey(FirstCategory, related_name&#61;&#39;sub_categories&#39;, verbose_name&#61;&#39;上级分类&#39;)
def __str__(self):
return self.name
class Meta:
ordering &#61; [&#39;name&#39;, ]
verbose_name &#61; &#39;二级分类&#39;
verbose_name_plural &#61; verbose_name
class GoodsInfo(models.Model):
STATUS_CHOICES &#61; (
(1, &#39;上架&#39;),
(2, &#39;下架&#39;),
)
title &#61; models.CharField(max_length&#61;100, verbose_name&#61;&#39;标题&#39;)
content &#61; models.TextField(blank&#61;True, null&#61;True, verbose_name&#61;&#39;正文&#39;)
image &#61; models.FileField(upload_to&#61;&#39;images/goods/%Y/%m&#39;, blank&#61;True, null&#61;True, verbose_name&#61;&#39;图片&#39;)
status &#61; models.IntegerField(choices&#61;STATUS_CHOICES, default&#61;1, verbose_name&#61;&#39;状态&#39;)
created_time &#61; models.DateTimeField(auto_now_add&#61;True, verbose_name&#61;&#39;创建时间&#39;)
publish_time &#61; models.DateTimeField(blank&#61;True, null&#61;True, default&#61;now, verbose_name&#61;&#39;发布时间&#39;)
updated_time &#61; models.DateTimeField(auto_now&#61;True, verbose_name&#61;&#39;更新时间&#39;)
category &#61; models.ForeignKey(SubCategory, on_delete&#61;models.CASCADE, related_name&#61;&#39;goods_info&#39;, verbose_name&#61;&#39;所属分类&#39;)
tags &#61; models.ManyToManyField(GoodsTag, blank&#61;True, verbose_name&#61;&#39;标签集合&#39;)
def __str__(self):
return self.title
class Meta:
verbose_name &#61; &#39;商品信息&#39;
verbose_name_plural &#61; verbose_name
主路由
urlpatterns &#61; [
url(r&#39;^test/&#39;, include(&#39;multiple_filter.urls&#39;, namespace&#61;&#39;test&#39;)),
]
应用路由
urlpatterns &#61; [
url(r&#39;^goods.html$&#39;, goods, name&#61;&#39;goods&#39;),
url(r&#39;^goods-(?P\d&#43;)-(?P\d&#43;)-(?P\d&#43;)-(?P\d&#43;).html&#39;, goods, name&#61;&#39;goods_filter&#39;),
]
视图
from .models import GoodsTag, FirstCategory, SubCategory, GoodsInfo
from django.shortcuts import get_object_or_404
def goods(request, **kwargs):
if not kwargs:
return redirect(&#39;test:goods_filter&#39;, first_category_id&#61;&#39;0&#39;, sub_category_id&#61;&#39;0&#39;, tags_id&#61;&#39;0&#39;, status_id&#61;&#39;0&#39;)
else:
request_path &#61; request.path
print(&#39;\n当前请求路径&#xff1a;&#39;, request_path, &#39;\n&#39;)
print(&#39;kwargs&#xff1a;&#39;, kwargs) # {&#39;first_category_id&#39;: &#39;0&#39;, &#39;sub_category_id&#39;: &#39;0&#39;, &#39;tags_id&#39;: &#39;0&#39;, &#39;status_id&#39;: &#39;0&#39;}
goods_tag_list &#61; GoodsTag.objects.all().values(&#39;id&#39;, &#39;name&#39;)
first_category_list &#61; FirstCategory.objects.all().values(&#39;id&#39;, &#39;name&#39;)
sub_category_list &#61; SubCategory.objects.all().values(&#39;id&#39;, &#39;name&#39;)
status_list &#61; list(map(lambda x: {&#39;id&#39;: x[0], &#39;status&#39;: x[1]}, GoodsInfo.STATUS_CHOICES))
filter_dict &#61; dict()
if kwargs[&#39;first_category_id&#39;] &#61;&#61; &#39;0&#39;:
# goods-0-x-x-x.html
if kwargs[&#39;sub_category_id&#39;] !&#61; &#39;0&#39;:
# goods-0-1-x-x.html
sub_category &#61; get_object_or_404(SubCategory, id&#61;kwargs[&#39;sub_category_id&#39;])
# 选择二级分类后&#xff0c;由于多对一关系&#xff0c;一级分类也会跟着变化
first_category_list &#61; [{&#39;id&#39;: sub_category.first_category.id, &#39;name&#39;: sub_category.first_category.name}]
filter_dict[&#39;category&#39;] &#61; sub_category
else:
# 一级分类不为0&#xff0c;需要进行筛选
# goods-1-x-x-x.html
first_category &#61; get_object_or_404(FirstCategory, id&#61;kwargs[&#39;first_category_id&#39;])
sub_category_list &#61; first_category.sub_categories.values(&#39;id&#39;, &#39;name&#39;) # 选择一级分类后获取二级分类的列表
if kwargs[&#39;sub_category_id&#39;] !&#61; &#39;0&#39;:
sub_category &#61; get_object_or_404(SubCategory, id&#61;kwargs[&#39;sub_category_id&#39;], first_category&#61;first_category)
# 选择二级分类后&#xff0c;由于多对一关系&#xff0c;一级分类也会跟着变化
first_category_list &#61; [{&#39;id&#39;: sub_category.first_category.id, &#39;name&#39;: sub_category.first_category.name}]
filter_dict[&#39;category&#39;] &#61; sub_category
if kwargs[&#39;tags_id&#39;] !&#61; &#39;0&#39;:
filter_dict[&#39;tags&#39;] &#61; kwargs[&#39;tags_id&#39;]
if kwargs[&#39;status_id&#39;] !&#61; &#39;0&#39;:
filter_dict[&#39;status&#39;] &#61; int(kwargs[&#39;status_id&#39;])
goods_list &#61; GoodsInfo.objects.filter(**filter_dict)
return render(request, &#39;goods.html&#39;,
{
&#39;first_category_list&#39;: first_category_list,
&#39;sub_category_list&#39;: sub_category_list,
&#39;goods_tag_list&#39;: goods_tag_list,
&#39;status_list&#39;: status_list,
&#39;goods_list&#39;: goods_list
})
模板
{% load goods_active %}
多条件筛选{% active_all request.path 1 %}
{% for first_category in first_category_list %}
{% active request.path first_category 1 %}
{% endfor %}
{% active_all request.path 2 %}
{% for sub_category in sub_category_list %}
{% active request.path sub_category 2 %}
{% endfor %}
{% active_all request.path 3 %}
{% for goods_tag in goods_tag_list %}
{% active request.path goods_tag 3 %}
{% endfor %}
{% active_all request.path 4 %}
{% for status in status_list %}
{% active request.path status 4 %}
{% endfor %}
{% for goods in goods_list %}
【{{ goods.title }}】{{ goods.content }}
{% endfor %}
链接生成模板标签
应用下创建templatetags包&#xff0c;创建 goods_active.py 文件&#xff0c;用来放置模板标签
from django.utils.safestring import mark_safe
from django import template
register &#61; template.Library()
&#64;register.simple_tag
def active_all(current_url, index):
"""
获取当前url&#xff0c;进行值修改拼接
:param current_url: http://127.0.0.1:8000/test/goods-0-0-0-0.html
:param index:
:return:
"""
a_href_active &#61; """
【全部】
"""
a_href_unactive &#61; """
全部
"""
url_part_list &#61; current_url.split(&#39;-&#39;)
if index &#61;&#61; len(url_part_list)-1: # 最后一个带.html要特殊处理
if url_part_list[index] &#61;&#61; &#39;0.html&#39;:
a_href &#61; a_href_active
else:
a_href &#61; a_href_unactive
url_part_list[index] &#61; &#39;0.html&#39;
else:
if url_part_list[index] &#61;&#61; &#39;0&#39;:
a_href &#61; a_href_active
else:
a_href &#61; a_href_unactive
url_part_list[index] &#61; &#39;0&#39;
href &#61; &#39;-&#39;.join(url_part_list)
a_href &#61; a_href.format(href&#61;href)
return mark_safe(a_href)
&#64;register.simple_tag
def active(current_url, item, index):
"""
获取当前url&#xff0c;进行值修改拼接
:param current_url: http://127.0.0.1:8000/test/goods-0-0-0-0.html
:param index:
:return:
"""
a_href_active &#61; """
【{name}】
"""
a_href_unactive &#61; """
{name}
"""
url_part_list &#61; current_url.split(&#39;-&#39;)
if index &#61;&#61; len(url_part_list)-1: # 最后一个带.html要特殊处理
if url_part_list[index] &#61;&#61; str(item[&#39;id&#39;]) &#43; &#39;.html&#39;:
a_href &#61; a_href_active
else:
a_href &#61; a_href_unactive
url_part_list[index] &#61; str(item[&#39;id&#39;]) &#43; &#39;.html&#39;
else:
# print(item[&#39;id&#39;], type(item[&#39;id&#39;])) # item[&#39;id&#39;]是int类型
if url_part_list[index] &#61;&#61; str(item[&#39;id&#39;]):
a_href &#61; a_href_active
else:
a_href &#61; a_href_unactive
url_part_list[index] &#61; str(item[&#39;id&#39;])
href &#61; &#39;-&#39;.join(url_part_list)
if index in range(1, 4):
a_href &#61; a_href.format(href&#61;href, name&#61;item[&#39;name&#39;])
if index &#61;&#61; len(url_part_list)-1:
a_href &#61; a_href.format(href&#61;href, name&#61;item[&#39;status&#39;])
return mark_safe(a_href)
多对多模型进行筛选
模型
# 课程分类
class Category(models.Model):
weight &#61; models.IntegerField(verbose_name&#61;&#39;权重(按从大到小排列)&#39;, default&#61;0)
name &#61; models.CharField(max_length&#61;32, verbose_name&#61;&#39;分类名称&#39;)
class Meta:
verbose_name &#61; &#39;分类方向&#39;
verbose_name_plural &#61; verbose_name
def __str__(self):
return self.name
# 编程语言&#xff0c;一个课程分类里可能有多种编程语言&#xff0c;一种编程语言可能存在不同的课程分类
class Code(models.Model):
weight &#61; models.IntegerField(default&#61;0, verbose_name&#61;&#39;权重(按从大到小排列)&#39;)
name &#61; models.CharField(max_length&#61;32, verbose_name&#61;&#39;编程语言&#39;)
category &#61; models.ManyToManyField(Category, related_name&#61;&#39;codes&#39;, verbose_name&#61;&#39;课程分类&#39;)
class Meta:
verbose_name &#61; &#39;编程语言&#39;
verbose_name_plural &#61; verbose_name
def __str__(self):
return self.name
# 课程详情
class Course(models.Model):
STATUS_CHOICE &#61; (
(0, &#39;下线&#39;),
(1, &#39;上线&#39;)
)
LEVEL_CHOICE &#61; (
(1, &#39;初级&#39;),
(2, &#39;中级&#39;),
(3, &#39;高级&#39;)
)
status &#61; models.IntegerField(choices&#61;STATUS_CHOICE, default&#61;1, verbose_name&#61;&#39;状态&#39;)
level &#61; models.IntegerField(choices&#61;LEVEL_CHOICE, default&#61;1, verbose_name&#61;&#39;难度级别&#39;)
category &#61; models.ForeignKey(Category, null&#61;True, blank&#61;True, related_name&#61;&#39;courses&#39;, verbose_name&#61;&#39;课程分类&#39;)
weight &#61; models.IntegerField(default&#61;0, verbose_name&#61;&#39;权重(按从大到小排列)&#39;)
title &#61; models.CharField(max_length&#61;32, verbose_name&#61;&#39;标题&#39;)
summary &#61; models.CharField(max_length&#61;100, verbose_name&#61;&#39;简介&#39;)
image &#61; models.ImageField(upload_to&#61;&#39;images/course/%Y/%m&#39;, verbose_name&#61;&#39;图片&#39;)
video_url &#61; models.CharField(max_length&#61;256, verbose_name&#61;&#39;视频地址&#39;)
create_time &#61; models.DateTimeField(auto_now_add&#61;True, verbose_name&#61;&#39;创建时间&#39;)
class Meta:
verbose_name &#61; &#39;课程详情&#39;
verbose_name_plural &#61; verbose_name
def __str__(self):
return self.title
路由
urlpatterns &#61; [
# 访问形式http://127.0.0.1:8000/test/course-0-0-0.html&#xff0c;
# 第一个0代表课程分类&#xff0c;第二个0代表编程语言&#xff0c;第三个0代表课程级别
# 0代表全部&#xff0c;然后递增&#xff0c;当选择课程分类中的第一项&#xff0c;第一个0就会变成1
url(r&#39;^course-(?P\d&#43;)-(?P\d&#43;)-(?P\d&#43;).html&#39;, course, name&#61;&#39;course&#39;),
]
视图
def course(request, *args, **kwargs):
print(args, kwargs) # () {&#39;code_id&#39;: &#39;0&#39;, &#39;category_id&#39;: &#39;0&#39;, &#39;level_id&#39;: &#39;0&#39;}
request_path &#61; request.path # http://127.0.0.1:8000/test/course-0-0-0.html
# 筛选字典
filter_dict &#61; dict()
code_list &#61; Code.objects.all().values(&#39;id&#39;, &#39;name&#39;)
category_list &#61; Category.objects.all().values(&#39;id&#39;, &#39;name&#39;)
level_list &#61; list(map(lambda x: {&#39;id&#39;: x[0], &#39;name&#39;: x[1]}, Course.LEVEL_CHOICE))
if kwargs[&#39;code_id&#39;] &#61;&#61; &#39;0&#39;:
if kwargs[&#39;category_id&#39;] !&#61; &#39;0&#39;:
category_list &#61; Category.objects.filter(id&#61;kwargs[&#39;category_id&#39;]).values(&#39;id&#39;, &#39;name&#39;)
category &#61; get_object_or_404(Category, id&#61;kwargs[&#39;category_id&#39;])
# 分类不是全部&#xff0c;得到这个分类对应的所有编程语言
code_list &#61; category.codes.values(&#39;id&#39;, &#39;name&#39;)
# 筛选这一分类
filter_dict[&#39;category&#39;] &#61; category
else:
# 如果编程语言不为0&#xff0c;则获取对应的编程语言
code &#61; get_object_or_404(Code, id&#61;kwargs[&#39;code_id&#39;])
# 得到编程语言对应的所有分类
categories &#61; code.category.all()
category_list &#61; categories.values(&#39;id&#39;, &#39;name&#39;)
# 筛选课程在这些分类的结果
filter_dict[&#39;category__in&#39;] &#61; categories
if kwargs[&#39;category_id&#39;] !&#61; &#39;0&#39;:
# 如果分类不为0&#xff0c;对分类进行筛选&#xff0c;得到该编程语言和该分类下的结果
category &#61; get_object_or_404(categories, id&#61;kwargs[&#39;category_id&#39;])
code_list &#61; category.codes.values(&#39;id&#39;, &#39;name&#39;)
filter_dict[&#39;category&#39;] &#61; category
if kwargs[&#39;level_id&#39;] !&#61; &#39;0&#39;:
filter_dict[&#39;level&#39;] &#61; int(kwargs[&#39;level_id&#39;])
filter_dict[&#39;status&#39;] &#61; 1
course_list &#61; Course.objects.filter(**filter_dict)
return render(request, &#39;course.html&#39;,
{
&#39;category_list&#39;: category_list,
&#39;code_list&#39;: code_list,
&#39;level_list&#39;: level_list,
&#39;course_list&#39;: course_list,
})
模板
{% load course_active %}
多条件筛选多对多模型编程语言&#xff1a;
{% active_all request.path 1 %}
{% for code in code_list %}
{% active request.path code 1 %}
{% endfor %}
课程分类&#xff1a;
{% active_all request.path 2 %}
{% for category in category_list %}
{% active request.path category 2 %}
{% endfor %}
课程信息&#xff1a;
{% active_all request.path 3 %}
{% for level in level_list %}
{% active request.path level 3 %}
{% endfor %}
{% for course in course_list %}
《{{ course.title }}》{{ course.summary }}
{% endfor %}
链接生成模板标签
应用下创建templatetags包&#xff0c;创建 course_active.py 文件&#xff0c;用来放置模板标签
from django.utils.safestring import mark_safe
from django import template
register &#61; template.Library()
&#64;register.simple_tag
def active_all(current_url, index):
"""
获取当前url&#xff0c; course-1-1-2.html
:param current_url:
:param index:
:return:
"""
url_part_list &#61; current_url.split(&#39;-&#39;)
if index &#61;&#61; 3:
if url_part_list[index] &#61;&#61; &#39;0.html&#39;:
temp &#61; &#39;【全部】&#39;
else:
temp &#61; &#39;全部&#39;
url_part_list[index] &#61; &#39;0.html&#39;
else:
if url_part_list[index] &#61;&#61; &#39;0&#39;:
temp &#61; &#39;【全部】&#39;
else:
temp &#61; &#39;全部&#39;
url_part_list[index] &#61; &#39;0&#39;
url_str &#61; &#39;-&#39;.join(url_part_list)
temp &#61; temp % (url_str, )
return mark_safe(temp)
&#64;register.simple_tag
def active(current_url, item, index):
"""
course-0-0-1.html
:param current_url:
:param item:
:param index:
:return:
"""
# print(&#39;\n当前访问地址&#xff1a;&#39;, current_url, item, index, type(index))
url_part_list &#61; current_url.split(&#39;-&#39;)
# print(url_part_list) # [&#39;/test/course&#39;, &#39;0&#39;, &#39;0&#39;, &#39;0.html&#39;]
if index &#61;&#61; 3:
if str(item[&#39;id&#39;]) &#61;&#61; url_part_list[3].split(&#39;.&#39;)[0]: # 如果当前标签被选中
temp &#61; &#39;【%s】&#39;
else:
temp &#61; &#39;%s&#39;
url_part_list[index] &#61; str(item[&#39;id&#39;]) &#43; &#39;.html&#39; # 拼接对应位置的url
else:
if str(item[&#39;id&#39;]) &#61;&#61; url_part_list[index]:
temp &#61; &#39;【%s】&#39;
else:
temp &#61; &#39;%s&#39;
url_part_list[index] &#61; str(item[&#39;id&#39;])
url_str &#61; &#39;-&#39;.join(url_part_list) # 拼接整体url
# print(url_str)
temp &#61; temp % (url_str, item[&#39;name&#39;]) # 生成对应的a标签
return mark_safe(temp)
{% with filter_event_form.user as filter_fields %}
{{ filter_fields.label }}
{% for select in filter_fields %}{{ select }}{% endfor %}
{% endwith %}
{% with filter_event_form.status as filter_fields %}
{{ filter_fields.label }}
{% for select in filter_fields %}{{ select }}{% endfor %}
{% endwith %}
{% with filter_event_form.project as filter_fields %}
{{ filter_fields.label }}
{% for select in filter_fields %}{{ select }}{% endfor %}
{% endwith %}
{% with filter_event_form.category as filter_fields %}
{{ filter_fields.label }}
{% for select in filter_fields %}{{ select }}{% endfor %}
{% endwith %}
{% with filter_event_form.level as filter_fields %}
{{ filter_fields.label }}
{% for select in filter_fields %}{{ select }}{% endfor %}
{% endwith %}
筛选事件
{% csrf_token %}