Django多条件筛选查询

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\d+)-(?P\d+)-(?P\d+)-(?P\d+)-(?P\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\d+)-(?P\d+)-(?P\d+)-(?P\d+)-(?P\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,
                      })

模板设计

事件列表

{% if old_filter %}
{% with filter_event_form.user as filter_fields %}
{% endwith %}
{% with filter_event_form.status as filter_fields %}
{% endwith %}
{% with filter_event_form.project as filter_fields %}
{% endwith %}
{% with filter_event_form.category as filter_fields %}
{% endwith %}
{% with filter_event_form.level as filter_fields %}
{% endwith %}
{% csrf_token %}
{% else %}

用户

状态

级别

分类

项目

{% 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 = '''
        
        '''
    else:
        temp = '''
        
        '''

    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 = '''
        
        '''
    else:
        temp = '''
        
        '''
    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')),
]

应用路由

访问 http://127.0.0.1:8000/test/goods.html 可跳转到 http://127.0.0.1:8000/test/goods-0-0-0-0.html

urlpatterns = [
    url(r'^goods.html$', goods, name='goods'),
    url(r'^goods-(?P\d+)-(?P\d+)-(?P\d+)-(?P\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
                      })

模板


{% 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包,创建 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_unactive = """
    全部
    """
    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 = """
    【{name}】
    """
    a_href_unactive = """
    {name}
    """
    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\d+)-(?P\d+)-(?P\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,
                  })

模板


{% load course_active %}


    
    多条件筛选多对多模型



选择:

编程语言: {% active_all request.path 1 %} {% for code in code_list %} {% active request.path code 1 %} {% endfor %}

课程分类: {% active_all request.path 2 %} {% for category in category_list %} {% active request.path category 2 %} {% endfor %}

课程信息: {% 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包,创建 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 = '【全部】'
        else:
            temp = '全部'

        url_part_list[index] = '0.html'
    else:
        if url_part_list[index] == '0':
            temp = '【全部】'
        else:
            temp = '全部'

        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 = '【%s】'
        else:
            temp = '%s'

        url_part_list[index] = str(item['id']) + '.html'  # 拼接对应位置的url

    else:
        if str(item['id']) == url_part_list[index]:
            temp = '【%s】'
        else:
            temp = '%s'

        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)

你可能感兴趣的:(Django多条件筛选查询)