Django 实现组合搜索
创始人
2025-06-01 05:26:08

现在很多网站都会有这样的组合搜索功能,其实质是几个模型之间组合对数据库进行查询,并将结果显示到页面上。

每一行都是一个模型,模型之间有着连表关系(一对多、多对多等)

模型设计

  • 总共四个模型:分别为方向、分类、等级以及存储结果信息
  • 一个方向下可以有多个分类,一个分类也可以是多个方向(多对多)
  • 一个分类可以有多个视频(一对多)
  • 一个等级下也可以有多个视频(一对多)
from django.db import modelsclass Direction(models.Model):"""方向:自动化、测试、运维、前端"""name = models.CharField(verbose_name='名称', max_length=32)classification = models.ManyToManyField('Classification')class Meta:db_table = 'Direction'verbose_name_plural = '方向(视频方向)'        # 模型的复数形式,若不指定则在后面加一个 sdef __str__(self):return self.nameclass Classification(models.Model):"""分类:Python、Linux、JavaScript、OpenStack、Node.js、C"""name = models.CharField(verbose_name='名称', max_length=32)class Meta:db_table = 'Classification'verbose_name_plural = '分类(视频分类)'def __str__(self):return self.nameclass Level(models.Model):"""等级:初级、中级、高级、骨灰级"""title = models.CharField(max_length=32)class Meta:verbose_name_plural = '难度级别'def __str__(self):return self.titleclass Video(models.Model):status_choice = ((1, '下线'),(2, '上线'),)status = models.IntegerField(verbose_name='状态', choices=status_choice, default=1)level = models.ForeignKey('Level', on_delete=models.CASCADE)classification = models.ForeignKey('Classification', null=True, blank=True, on_delete=models.CASCADE)weight = models.IntegerField(verbose_name='权重(从大到小排列)', default=0)title = models.CharField(verbose_name='标题', max_length=32)summary = models.CharField(verbose_name='简介', max_length=100)# 也可以用 ImgField 或 FileField 存储图片,而不是 CharField,但是要指定存储路径# img = models.ImgField(verbose_name='图片', upload_to='app/static/app/video')img = models.CharField(verbose_name='图片', max_length=200)href = models.CharField(verbose_name='视频地址', max_length=256)create_data = models.DateTimeField(auto_now_add=True)class Meta:db_table = 'Video'verbose_name_plural = '视频'def __str__(self):return self.title

URlconf 配置

urlconf 配置采用的是二级路由,即应用本身创建 urls.py

# project/urls.py
from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('app/', include('app.urls')),
]# app/urls.py
from django.urls import path
from app import viewsurlpatterns = [path('video////', views.video, name='video'),path('video2////', views.video2, name='video2'),
]

一对多

一对多关系中主要是视频信息与分类、等级之间的关系操作。

视图函数

函数接收三个额外参数,分别为:分类 classification id、等级 level id 以及状态 status id。根据这三个参数构造查询条件(filter() 函数本身是支持字典形式查询的)。

Tips

condition 构造的查询条件是字典形式,其键 key应与数据表中相应字段对应,如: classification_id 为模型 VideoClassification 的外键字段名。

from django.shortcuts import render, HttpResponse
from app.models import Level, Classification, Direction, Videodef video(request, *args, **kwargs):print(args, kwargs)     # () {'classification_id': 1, 'level_id': 2}# 构造查询条件condition = {# 'classification_id': 0,# 'level_id': 0}# 当 kwargs = {'classification_id': 0, 'level_id': 0} 时,condition = {},# Video.objects.filter(**condition) 能把所有的都查出来# 当 kwargs = {'classification_id': 1, 'level_id': 1} 时,condition = {'classification_id': 1, 'level_id': 1}# filter() 支持字典格式# 将其转换为整数for k, v in kwargs.items():temp = int(v)kwargs[k] = tempif temp:condition[k] = tempclass_list = Classification.objects.all()level_list = Level.objects.all()# 查询数据video_list = Video.objects.filter(**condition)"""status_choice = ((1, '下线'),(2, '上线'),)"""# status_list:[{'id': 1, 'name': '下线'}, {'id': 2, 'name': '上线'}]status_list = list(map(lambda x: {'id': x[0], 'name': x[1]}, Video.status_choice))return render(request,'app/video.html',{'kwargs': kwargs,'class_list': class_list,'level_list': level_list,'video_list': video_list,'status_list': status_list})

模板

{% load static %}


视频

筛选

结果

{% for video in video_list %}

{{ video.title }}

{ video.href }}">{% endfor %}

多对多

多对多关系中主要是方向与分类之间的关系操作。

视图函数

from django.shortcuts import render, HttpResponse
from app.models import Level, Classification, Direction, Videodef video2(request, *args, **kwargs):"""多对多:"方向-分类方向:自动化、测试、运维、前端分类:Python、Linux、JavaScript、OpenStack、Node.js、C等级:初级、中级、高级、骨灰级"""print(kwargs)       # {'direction_id': 1, 'classification_id': 4, 'level_id': 2}direction_id = kwargs.get('direction_id')classification_id = kwargs.get('classification_id')level_id = kwargs.get('level_id')condition = {}      # 条件    构造查询字典# 方向:全部列举direction_list = Direction.objects.all()# 若方向为 0,则分类显示全部if direction_id == 0:# 若分类也为 0,分类显示全部class_list = Classification.objects.all()if classification_id == 0:passelse:condition['classification_id'] = classification_id# 若方向不为 0,则根据方向查询分类else:direction_obj = Direction.objects.filter(id=direction_id)[0]class_list = direction_obj.classification.all()     # 根据多对多名字+方向的ID,获取相应分类列表# < QuerySet[ < Classification: Python >, < Classification: Linux >] ># 根据方向 id 获取分类的 id 列表vlist = direction_obj.classification.all().values_list('id')   #  < QuerySet[(1,), (5,)] ># 若哪个方向下没有分类if not vlist:classification_id_list = []else:# 转换为元组classification_id_list = list(zip(*vlist))[0]       # (1, 5)# 若分类为 0,则显示相应分类if classification_id == 0:condition['classification_id__in'] = classification_id_listelse:if classification_id in classification_id_list:condition['classification_id'] = classification_idelse:condition['classification_id__in'] = classification_id_listif level_id == 0:passelse:condition['level_id'] = level_id# 等级:全部列举level_list = Level.objects.all()video_list = Video.objects.filter(**condition)return render(request,'app/video2.html',{'direction_list': direction_list,'level_list': level_list,'kwargs': kwargs,'video_list': video_list,'class_list': class_list})

模板



多对多和一对多

筛选

{% if kwargs.direction_id == 0 %}全部{% else %}全部{% endif %}{% for direction in direction_list %}{% if direction.id == kwargs.direction_id %}{{ direction.name }}{% else %}{{ direction.name }}{% endif %}{% endfor %}
{% if kwargs.classification_id == 0 %}全部{% else %}全部{% endif %}{% for class in class_list %}{% if class.id == kwargs.classification_id %}{{ class.name }}{% else %}{{ class.name }}{% endif %}{% endfor %}
{% if kwargs.level_id == 0 %}全部{% else %}全部{% endif %}{% for level in level_list %}{% if level.id == kwargs.level_id %}{{ level.title }}{% else %}{{ level.title }}{% endif %}{% endfor %}

结果

{% for video in video_list %}

{{ video.title }}

{% endfor %}

参考博客

  • Django之组合查询
  • django实现瀑布流、组合搜索、阶梯评论、验证码

相关内容

热门资讯

麒麟软件取得一种基于docke... 国家知识产权局信息显示,麒麟软件有限公司取得一项名为“一种基于docker的linux内核编译方法及...
被总统点赞的法国艺术家,用镜头... (来源:上观新闻)一个1910年的少年,站在上海东方明珠的街头。这样一幅拼贴的黑白“摄影”作品,让观...
甘肃国际物流集团累计发运国际货... 本报讯(新甘肃·甘肃日报记者王占东)甘肃的洋葱、种子等农产品销往东南亚,中亚的粮油在兰州实现中转分拨...
酒嘉双城经济圈建设工作稳步推进 本报嘉峪关讯(新甘肃·甘肃日报记者于晓明)日前,酒嘉双城经济圈建设工作第四次联席会议在嘉峪关市召开。...
甘味之夜 京华流芳 新甘肃·甘肃日报记者 王朝霞 丝路古道的清风拂过舞台,飞天仙子翩跹起舞,再现甘肃厚重的文化底蕴;陇原...