欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Django多条件筛选查询

程序员文章站 2022-06-15 10:38:19
转自:https://www.jianshu.com/p/a86281df530e Django多条件筛选查询 主模型只存在外键一对多关系 模型设计 # 快捷筛选状态 class Status(models.Model): order_number = models.PositiveIntegerF ......

转自:

 

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 <= -1:
            return '处理已超时!'

        return '{}天{}时{}分'.format(days, hours, minute)

    def __str__(self):
        return self.title

    def get_content_as_markdown(self):
        """
        当使用mardown功能时,我们需要先让它转义一下特殊字符,然后再解析出markdown标签。
        这样做之后,输出字符串可以安全的在模板中使用。
        :return:
        """
        return mark_safe(markdown(self.content, safe_mode='escape'))

路由设计

    url(r'^event/$', event, name='event'),
    url(r'^event-(?p<user_id>\d+)-(?p<status_id>\d+)-(?p<level_id>\d+)-(?p<category_id>\d+)-(?p<project_id>\d+).html$', event, name='event_filter'),

视图设计

该视图只需要查看kwargs有值的情况

def get_group_url_list(url):
    """
    将访问的url存储在列表中,用于前端判断
    event_menu_group : 事件菜单组
    other_menu_group : 其他菜单组
    :param url:
    :return:
    """
    group_url_list = list()
    group_url_list.append(url)
    return group_url_list


# 显示事件列表
def event(request, **kwargs):
    print('视图**kwargs的值:', kwargs)
    if not kwargs:
        # 原来的事件列表和post筛选
        # events = eventcontent.objects.all()
        queryset = eventcontent.objects.all()
        if request.method == 'post':
            visit_url = reverse('event')
            event_url_list = get_group_url_list(visit_url)

            filter_event_form = filtereventform(request.post)
            if filter_event_form.is_valid():
                print('表单验证通过')
                user = filter_event_form.cleaned_data['user']
                status = filter_event_form.cleaned_data['status']
                project = filter_event_form.cleaned_data['project']
                category = filter_event_form.cleaned_data['category']
                level = filter_event_form.cleaned_data['level']
                queryset = queryset.filter(user=user, status=status, project=project, category=category, level=level)
                print(queryset)
        else:
            visit_url = reverse('event')
            event_url_list = get_group_url_list(visit_url)

            filter_event_form = filtereventform()

        page = request.get.get('page', 1)
        paginator = paginator(queryset, settings.page_num)  # paginator是分页对象
        try:
            events = paginator.page(page)
        except pagenotaninteger:
            events = paginator.page(1)
        except emptypage:
            events = paginator.page(paginator.num_pages)
        return render(request, 'event.html',
                      {
                          'events': events,
                          'event_menu_group': event_url_list,
                          'filter_event_form': filter_event_form,
                          'old_filter': true
                      })
    else:
        """
        多条件事件筛选
        event-(?p<user_id>\d+)-(?p<status_id>\d+)-(?p<level_id>\d+)-(?p<category_id>\d+)-(?p<project_id>\d+).html
        {'user_id': '0', 'status_id': '0', 'level_id': '0', 'category_id': '0', 'project_id': '0'}
        """
        filter_dict = dict()
        request_path = request.path
        print('请求地址:', request_path)
        if kwargs['user_id'] != '0':
            filter_dict['user'] = get_object_or_404(user, id=kwargs['user_id'])
        if kwargs['status_id'] != '0':
            filter_dict['status'] = get_object_or_404(status, id=kwargs['status_id'])
        if kwargs['level_id'] != '0':
            filter_dict['level'] = get_object_or_404(level, id=kwargs['level_id'])
        if kwargs['category_id'] != '0':
            filter_dict['category'] = get_object_or_404(category, id=kwargs['category_id'])
        if kwargs['project_id'] != '0':
            filter_dict['project'] = get_object_or_404(project, id=kwargs['project_id'])

        user_list = user.objects.all().values('id', 'username')
        # print(user_list)
        status_list = status.objects.all().values('id', 'status_tag')
        # print(status_list)
        level_list = level.objects.all().values('id', 'level_tag')
        category_list = category.objects.all().values('id', 'category_name')
        project_list = project.objects.all().values('id', 'project_name')

        url_id_list = kwargs.values()  # url中所有id:[0, 0, 0, 0, 0 ]
        visit_url = reverse('event_filter', args=url_id_list)
        event_url_list = get_group_url_list(visit_url)
        queryset = eventcontent.objects.filter(**filter_dict)
        page = request.get.get('page', 1)
        paginator = paginator(queryset, settings.page_num)  # paginator是分页对象
        try:
            events = paginator.page(page)
        except pagenotaninteger:
            events = paginator.page(1)
        except emptypage:
            events = paginator.page(paginator.num_pages)
        return render(request, 'event.html',
                      {
                          'events': events,
                          'event_menu_group': event_url_list,
                          'user_list': user_list,
                          'status_list': status_list,
                          'level_list': level_list,
                          'category_list': category_list,
                          'project_list': project_list,
                      })

模板设计

<div class="card-header">
    <h3 class="card-title">事件列表</h3>
</div>
<!-- /.card-header -->
{% if old_filter %}
    <div class="card-body card-comment">
        <form role="form" action="{% url 'event' %}?page=2" method="post">
            <div class="row">
                <div class="col-2">
                    <div class="input-group mb-12">
                        {% with filter_event_form.user as filter_fields %}
                        <div class="input-group-prepend">
                            <label class="input-group-text {% if filter_fields.errors %}bg-danger {% endif %}" for="{{ filter_fields.id_for_label }}">{{ filter_fields.label }}</label>
                        </div>
                        <select class="form-control col-sm-12" name="user" id="{{ filter_fields.id_for_label }}">
                            <option>{% for select in filter_fields %}{{ select }}{% endfor %}</option>
                        </select>
                        {% endwith %}
                    </div>
                </div>
                <div class="col-2">
                    <div class="input-group mb-12">
                        {% with filter_event_form.status as filter_fields %}
                        <div class="input-group-prepend">
                            <label class="input-group-text {% if filter_fields.errors %}bg-danger{% endif %}" for="{{ filter_fields.id_for_label }}">{{ filter_fields.label }}</label>
                        </div>
                        <select class="form-control col-sm-12" name="status" id="{{ filter_fields.id_for_label }}">
                            <option>{% for select in filter_fields %}{{ select }}{% endfor %}</option>
                        </select>
                        {% endwith %}
                    </div>
                </div>
                <div class="col-2">
                    <div class="input-group mb-12">
                        {% with filter_event_form.project as filter_fields %}
                        <div class="input-group-prepend">
                            <label class="input-group-text {% if filter_fields.errors %}bg-danger {% endif %}" for="{{ filter_fields.id_for_label }}">{{ filter_fields.label }}</label>
                        </div>
                        <select class="form-control col-sm-12" name="project" id="{{ filter_fields.id_for_label }}">
                            <option>{% for select in filter_fields %}{{ select }}{% endfor %}</option>
                        </select>
                        {% endwith %}
                    </div>
                </div>
                <div class="col-2">
                    <div class="input-group mb-12">
                        {% with filter_event_form.category as filter_fields %}
                        <div class="input-group-prepend">
                            <label class="input-group-text {% if filter_fields.errors %}bg-danger {% endif %}" for="{{ filter_fields.id_for_label }}">{{ filter_fields.label }}</label>
                        </div>
                        <select class="form-control col-sm-12" name="category" id="{{ filter_fields.id_for_label }}">
                            <option>{% for select in filter_fields %}{{ select }}{% endfor %}</option>
                        </select>
                        {% endwith %}
                    </div>
                </div>
                <div class="col-2">
                    <div class="input-group mb-12">
                        {% with filter_event_form.level as filter_fields %}
                        <div class="input-group-prepend">
                            <label class="input-group-text {% if filter_fields.errors %}bg-danger {% endif %}" for="{{ filter_fields.id_for_label }}">{{ filter_fields.label }}</label>
                        </div>
                        <select class="form-control col-sm-12" name="level" id="{{ filter_fields.id_for_label }}">
                            <option>{% for select in filter_fields %}{{ select }}{% endfor %}</option>
                        </select>
                        {% endwith %}
                    </div>
                </div>
                <button type="submit" class="btn btn-primary">筛选事件</button>
            </div>
            {% csrf_token %}
        </form>
    </div>
{% else %}
    <div class="card-body d-flex p-0">
        <h3 class="card-title p-3">用户</h3>
        <ul class="nav nav-pills p-2">
            {% active_all request.path 1 %}
            {% for user_item in user_list %}
                {% active request.path user_item 1 %}
            {% endfor %}
        </ul>
    </div>
    <div class="card-body d-flex p-0">
        <h3 class="card-title p-3">状态</h3>
        <ul class="nav nav-pills p-2">
            {% active_all request.path 2 %}
            {% for status_item in status_list %}
                {% active request.path status_item 2 %}
            {% endfor %}
        </ul>
    </div>
    <div class="card-body d-flex p-0">
        <h3 class="card-title p-3">级别</h3>
        <ul class="nav nav-pills p-2">
            {% active_all request.path 3 %}
            {% for level_item in level_list %}
                {% active request.path level_item 3 %}
            {% endfor %}
        </ul>
    </div>
    <div class="card-body d-flex p-0">
        <h3 class="card-title p-3">分类</h3>
        <ul class="nav nav-pills p-2">
            {% active_all request.path 4 %}
            {% for category_item in category_list %}
                {% active request.path category_item 4 %}
            {% endfor %}
        </ul>
    </div>
    <div class="card-body d-flex p-0">
        <h3 class="card-title p-3">项目</h3>
        <ul class="nav nav-pills p-2">
            {% active_all request.path 5 %}
            {% for project_item in project_list %}
                {% active request.path project_item 5 %}
            {% endfor %}
        </ul>
    </div>
{% endif %}

链接生成模板标签

使用模板标签,在应用下创建templatetags的python包,然后创建active.py文件,需要在模板中通过{% load active %}引入模板标签。

from django.utils.safestring import mark_safe
from django import template


register = template.library()


@register.simple_tag
def active_all(request_path, index):
    url_part_list = request_path.split('-')
    # print(url_part_list)
    # ['/event', '0', '0', '0', '0', '0.html']
    # 第五组带.html,需要分开判断

    if url_part_list[index] == '0' or url_part_list[index] == '0.html':
        temp = '''
        <li class="nav-item">
            <a class="nav-link active" href="{href}">全部</a>
        </li>
        '''
    else:
        temp = '''
        <li class="nav-item">
            <a class="nav-link" href="{href}">全部</a>
        </li>
        '''

    if index != 5:
        url_part_list[index] = '0'
    else:
        url_part_list[index] = '0.html'

    href = '-'.join(url_part_list)
    return mark_safe(temp.format(href=href))


@register.simple_tag
def active(request_path, item, index):
    url_part_list = request_path.split('-')
    # 下面判断中,前面表示 event-0-1-5-1-,后面表示 3.html
    if url_part_list[index] == str(item['id']) or url_part_list[index] == str(item['id']) + '.html':
        temp = '''
        <li class="nav-item">
            <a href="{href}" class="nav-link active">{name}</a>
        </li>
        '''
    else:
        temp = '''
        <li class="nav-item">
            <a href="{href}" class="nav-link">{name}</a>
        </li>
        '''
    if index == 5:
        # 第五组有后缀.html,需单独处理
        url_part_list[index] = str(item['id']) + '.html'
    else:
        url_part_list[index] = str(item['id'])
    href = '-'.join(url_part_list)

    if index == 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=href, name=item['username']))
    if index == 2:
        return mark_safe(temp.format(href=href, name=item['status_tag']))
    if index == 3:
        return mark_safe(temp.format(href=href, name=item['level_tag']))
    if index == 4:
        return mark_safe(temp.format(href=href, name=item['category_name']))
    if index == 5:
        return mark_safe(temp.format(href=href, name=item['project_name']))

两级分类筛选

模型设计

from django.db import models
from django.utils.timezone import now


class goodstag(models.model):
    name = models.charfield(max_length=64, verbose_name='标签名称')

    def __str__(self):
        return self.name

    class meta:
        ordering = ['name', ]
        verbose_name = '商品标签'  # 后台显示模型名称
        verbose_name_plural = verbose_name


# 智能家居、手机、电视、电脑
class firstcategory(models.model):
    name = models.charfield(max_length=64, verbose_name='分类名称')

    def __str__(self):
        return self.name

    class meta:
        ordering = ['name', ]
        verbose_name = '一级分类'
        verbose_name_plural = verbose_name


# 小米6、小米8、红米10
class subcategory(models.model):
    name = models.charfield(max_length=64, verbose_name='分类名称')
    first_category = models.foreignkey(firstcategory, related_name='sub_categories', verbose_name='上级分类')

    def __str__(self):
        return self.name

    class meta:
        ordering = ['name', ]
        verbose_name = '二级分类'
        verbose_name_plural = verbose_name


class goodsinfo(models.model):
    status_choices = (
        (1, '上架'),
        (2, '下架'),
    )

    title = models.charfield(max_length=100, verbose_name='标题')
    content = models.textfield(blank=true, null=true, verbose_name='正文')
    image = models.filefield(upload_to='images/goods/%y/%m', blank=true, null=true, verbose_name='图片')
    status = models.integerfield(choices=status_choices, default=1, verbose_name='状态')
    created_time = models.datetimefield(auto_now_add=true, verbose_name='创建时间')
    publish_time = models.datetimefield(blank=true, null=true, default=now, verbose_name='发布时间')
    updated_time = models.datetimefield(auto_now=true, verbose_name='更新时间')
    category = models.foreignkey(subcategory, on_delete=models.cascade, related_name='goods_info', verbose_name='所属分类')
    tags = models.manytomanyfield(goodstag, blank=true, verbose_name='标签集合')

    def __str__(self):
        return self.title

    class meta:
        verbose_name = '商品信息'
        verbose_name_plural = verbose_name

主路由

urlpatterns = [
    url(r'^test/', include('multiple_filter.urls', namespace='test')),
]

应用路由

访问 可跳转到

urlpatterns = [
    url(r'^goods.html$', goods, name='goods'),
    url(r'^goods-(?p<first_category_id>\d+)-(?p<sub_category_id>\d+)-(?p<tags_id>\d+)-(?p<status_id>\d+).html', goods, name='goods_filter'),
]

视图

from .models import goodstag, firstcategory, subcategory, goodsinfo
from django.shortcuts import get_object_or_404


def goods(request, **kwargs):
    if not kwargs:
        return redirect('test:goods_filter', first_category_id='0', sub_category_id='0', tags_id='0', status_id='0')
    else:
        request_path = request.path
        print('\n当前请求路径:', request_path, '\n')
        print('kwargs:', kwargs)  # {'first_category_id': '0', 'sub_category_id': '0', 'tags_id': '0', 'status_id': '0'}

        goods_tag_list = goodstag.objects.all().values('id', 'name')
        first_category_list = firstcategory.objects.all().values('id', 'name')
        sub_category_list = subcategory.objects.all().values('id', 'name')
        status_list = list(map(lambda x: {'id': x[0], 'status': x[1]}, goodsinfo.status_choices))
        filter_dict = dict()

        if kwargs['first_category_id'] == '0':
            # goods-0-x-x-x.html
            if kwargs['sub_category_id'] != '0':
                # goods-0-1-x-x.html
                sub_category = get_object_or_404(subcategory, id=kwargs['sub_category_id'])
                # 选择二级分类后,由于多对一关系,一级分类也会跟着变化
                first_category_list = [{'id': sub_category.first_category.id, 'name': sub_category.first_category.name}]
                filter_dict['category'] = sub_category
        else:
            # 一级分类不为0,需要进行筛选
            # goods-1-x-x-x.html
            first_category = get_object_or_404(firstcategory, id=kwargs['first_category_id'])
            sub_category_list = first_category.sub_categories.values('id', 'name')  # 选择一级分类后获取二级分类的列表
            if kwargs['sub_category_id'] != '0':
                sub_category = get_object_or_404(subcategory, id=kwargs['sub_category_id'], first_category=first_category)
                # 选择二级分类后,由于多对一关系,一级分类也会跟着变化
                first_category_list = [{'id': sub_category.first_category.id, 'name': sub_category.first_category.name}]
                filter_dict['category'] = sub_category

        if kwargs['tags_id'] != '0':
            filter_dict['tags'] = kwargs['tags_id']

        if kwargs['status_id'] != '0':
            filter_dict['status'] = int(kwargs['status_id'])

        goods_list = goodsinfo.objects.filter(**filter_dict)

        return render(request, 'goods.html',
                      {
                          'first_category_list': first_category_list,
                          'sub_category_list': sub_category_list,
                          'goods_tag_list': goods_tag_list,
                          'status_list': status_list,
                          'goods_list': goods_list
                      })

模板

<!doctype html>
{% load goods_active %}
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>多条件筛选</title>
</head>
<body>
{% active_all request.path 1 %}
{% for first_category in first_category_list %}
    {% active request.path first_category 1 %}
{% endfor %}
<br><br>
{% active_all request.path 2 %}
{% for sub_category in sub_category_list %}
    {% active request.path sub_category 2 %}
{% endfor %}
<br><br>
{% active_all request.path 3 %}
{% for goods_tag in goods_tag_list %}
    {% active request.path goods_tag 3 %}
{% endfor %}
<br><br>
{% active_all request.path 4 %}
{% for status in status_list %}
    {% active request.path status 4 %}
{% endfor %}
<p>
    {% for goods in goods_list %}
        <p>
            【{{ goods.title }}】{{ goods.content }}
        </p>
    {% endfor %}
</p>
</body>
</html>

链接生成模板标签

应用下创建templatetags包,创建 goods_active.py 文件,用来放置模板标签

from django.utils.safestring import mark_safe
from django import template


register = template.library()


@register.simple_tag
def active_all(current_url, index):
    """
    获取当前url,进行值修改拼接
    :param current_url: http://127.0.0.1:8000/test/goods-0-0-0-0.html
    :param index:
    :return:
    """
    a_href_active = """
    <a href="{href}" class="active">【全部】</a>
    """
    a_href_unactive = """
    <a href="{href}">全部</a>
    """
    url_part_list = current_url.split('-')
    if index == len(url_part_list)-1:  # 最后一个带.html要特殊处理
        if url_part_list[index] == '0.html':
            a_href = a_href_active
        else:
            a_href = a_href_unactive

        url_part_list[index] = '0.html'
    else:
        if url_part_list[index] == '0':
            a_href = a_href_active
        else:
            a_href = a_href_unactive

        url_part_list[index] = '0'

    href = '-'.join(url_part_list)
    a_href = a_href.format(href=href)
    return mark_safe(a_href)


@register.simple_tag
def active(current_url, item, index):
    """
    获取当前url,进行值修改拼接
    :param current_url: http://127.0.0.1:8000/test/goods-0-0-0-0.html
    :param index:
    :return:
    """
    a_href_active = """
    <a href="{href}" class="active">【{name}】</a>
    """
    a_href_unactive = """
    <a href="{href}">{name}</a>
    """
    url_part_list = current_url.split('-')
    if index == len(url_part_list)-1:  # 最后一个带.html要特殊处理
        if url_part_list[index] == str(item['id']) + '.html':
            a_href = a_href_active
        else:
            a_href = a_href_unactive

        url_part_list[index] = str(item['id']) + '.html'
    else:
        # print(item['id'], type(item['id']))  # item['id']是int类型
        if url_part_list[index] == str(item['id']):
            a_href = a_href_active
        else:
            a_href = a_href_unactive

        url_part_list[index] = str(item['id'])

    href = '-'.join(url_part_list)
    if index in range(1, 4):
        a_href = a_href.format(href=href, name=item['name'])
    if index == len(url_part_list)-1:
        a_href = a_href.format(href=href, name=item['status'])
    return mark_safe(a_href)

多对多模型进行筛选

模型

# 课程分类
class category(models.model):
    weight = models.integerfield(verbose_name='权重(按从大到小排列)', default=0)
    name = models.charfield(max_length=32, verbose_name='分类名称')

    class meta:
        verbose_name = '分类方向'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


# 编程语言,一个课程分类里可能有多种编程语言,一种编程语言可能存在不同的课程分类
class code(models.model):
    weight = models.integerfield(default=0, verbose_name='权重(按从大到小排列)')
    name = models.charfield(max_length=32, verbose_name='编程语言')
    category = models.manytomanyfield(category, related_name='codes', verbose_name='课程分类')

    class meta:
        verbose_name = '编程语言'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


# 课程详情
class course(models.model):
    status_choice = (
        (0, '下线'),
        (1, '上线')
    )

    level_choice = (
        (1, '初级'),
        (2, '中级'),
        (3, '高级')
    )

    status = models.integerfield(choices=status_choice, default=1, verbose_name='状态')
    level = models.integerfield(choices=level_choice, default=1, verbose_name='难度级别')
    category = models.foreignkey(category, null=true, blank=true, related_name='courses', verbose_name='课程分类')
    weight = models.integerfield(default=0, verbose_name='权重(按从大到小排列)')
    title = models.charfield(max_length=32, verbose_name='标题')
    summary = models.charfield(max_length=100, verbose_name='简介')
    image = models.imagefield(upload_to='images/course/%y/%m', verbose_name='图片')
    video_url = models.charfield(max_length=256, verbose_name='视频地址')
    create_time = models.datetimefield(auto_now_add=true, verbose_name='创建时间')

    class meta:
        verbose_name = '课程详情'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.title

路由

urlpatterns = [
    # 访问形式http://127.0.0.1:8000/test/course-0-0-0.html,
    # 第一个0代表课程分类,第二个0代表编程语言,第三个0代表课程级别
    # 0代表全部,然后递增,当选择课程分类中的第一项,第一个0就会变成1
    url(r'^course-(?p<code_id>\d+)-(?p<category_id>\d+)-(?p<level_id>\d+).html', course, name='course'),
]

视图

def course(request, *args, **kwargs):
    print(args, kwargs)  # () {'code_id': '0', 'category_id': '0', 'level_id': '0'}
    request_path = request.path  # http://127.0.0.1:8000/test/course-0-0-0.html

    # 筛选字典
    filter_dict = dict()

    code_list = code.objects.all().values('id', 'name')
    category_list = category.objects.all().values('id', 'name')
    level_list = list(map(lambda x: {'id': x[0], 'name': x[1]}, course.level_choice))

    if kwargs['code_id'] == '0':
        if kwargs['category_id'] != '0':
            category_list = category.objects.filter(id=kwargs['category_id']).values('id', 'name')
            category = get_object_or_404(category, id=kwargs['category_id'])
            # 分类不是全部,得到这个分类对应的所有编程语言
            code_list = category.codes.values('id', 'name')
            # 筛选这一分类
            filter_dict['category'] = category
    else:
        # 如果编程语言不为0,则获取对应的编程语言
        code = get_object_or_404(code, id=kwargs['code_id'])
        # 得到编程语言对应的所有分类
        categories = code.category.all()
        category_list = categories.values('id', 'name')
        # 筛选课程在这些分类的结果
        filter_dict['category__in'] = categories
        if kwargs['category_id'] != '0':
            # 如果分类不为0,对分类进行筛选,得到该编程语言和该分类下的结果
            category = get_object_or_404(categories, id=kwargs['category_id'])
            code_list = category.codes.values('id', 'name')
            filter_dict['category'] = category

    if kwargs['level_id'] != '0':
        filter_dict['level'] = int(kwargs['level_id'])

    filter_dict['status'] = 1

    course_list = course.objects.filter(**filter_dict)
    return render(request, 'course.html',
                  {
                      'category_list': category_list,
                      'code_list': code_list,
                      'level_list': level_list,
                      'course_list': course_list,
                  })

模板

<!doctype html>
{% load course_active %}
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>多条件筛选多对多模型</title>
</head>
<body>

<h3>选择:</h3>

<p>
    编程语言:
    {% active_all request.path 1 %}
    {% for code in code_list %}
        <!--{{ code }}-->
        {% active request.path code 1 %}
    {% endfor %}
</p>

<p>
    课程分类:
    {% active_all request.path 2 %}
    {% for category in category_list %}
        <!--{{ category }}-->
        {% active request.path category 2 %}
    {% endfor %}
</p>

<p>
    课程信息:
    {% active_all request.path 3 %}
    {% for level in level_list %}
        <!--{{ level }}-->
        {% active request.path level 3 %}
    {% endfor %}
</p>

<h3>视频:</h3>
{% for course in course_list %}
    <a class="item" href="{{ course.video.url }}">
        <img src="/media/{{ course.image }}" width="300px" height="200px">
        <p>《{{ course.title }}》{{ course.summary }}</p>
        <hr>
    </a>
{% endfor %}

</body>
</html>

链接生成模板标签

应用下创建templatetags包,创建 course_active.py 文件,用来放置模板标签

from django.utils.safestring import mark_safe
from django import template


register = template.library()


@register.simple_tag
def active_all(current_url, index):
    """
    获取当前url, course-1-1-2.html
    :param current_url:
    :param index:
    :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'

    url_str = '-'.join(url_part_list)

    temp = temp % (url_str, )
    return mark_safe(temp)


@register.simple_tag
def active(current_url, item, index):
    """
    course-0-0-1.html
    :param current_url:
    :param item:
    :param index:
    :return:
    """
    # print('\n当前访问地址:', current_url, item, index, type(index))
    url_part_list = current_url.split('-')
    # print(url_part_list)  # ['/test/course', '0', '0', '0.html']
    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'])

    url_str = '-'.join(url_part_list)  # 拼接整体url
    # print(url_str)
    temp = temp % (url_str, item['name'])  # 生成对应的a标签
    return mark_safe(temp)