使用ListView中的Django QuerySets实现多种类型的后端动态过滤器

时间:2014-08-21 09:12:20

标签: jquery django listview filter

我试图在ListView中的模型中显示一组特定的对象,我需要使用适当的过滤器构造一个查询集。我试图通过其技术类型,对象类型和主题来过滤协议。这三个过滤器都是树形的,因此我导入了MPTTModel。

在models.py中,我有这些模型:

from django.db import models
from mptt.models import MPTTModel

class BPSubject(MPTTModel, models.Model):
    name = models.CharField(max_length=100, unique=False)
    engname = models.CharField(max_length=100, unique=False)
    parent = TreeForeignKey('self',null=True, blank=True, related_name='children', db_index=True)
    scopenote = models.TextField(blank = True)
    annotation = models.TextField(blank=True)

class BPTechnoType(MPTTModel, models.Model):
    name = models.CharField(max_length=100)
    engname = models.CharField(max_length=100)
    parent = TreeForeignKey('self',null=True, blank=True, related_name='children', db_index=True)

class BPObjectType(MPTTModel, models.Model):
    name = models.CharField(max_length=100)
    engname = models.CharField(max_length=100)
    parent = TreeForeignKey('self',null=True, blank=True, related_name='children', db_index=True)
    bptechno = models.ManyToManyField(BPTechnoType, blank=True) 

class Bioprotocol(models.Model):
        Title = models.CharField(max_length=200)
        TechnoType = models.ManyToManyField(BPTechnoType)
        ObjectType = models.ManyToManyField(BPObjectType)
        Abstract = models.TextField(blank=True)
        Subject = models.ManyToManyField(BPSubject)

然后我为索引页面定义了一个显示所有类别(Subject,ObjectType和TechnoType)的视图:

在views.py中:

class BPCategoryList(ListView):
    model = BPSubject
    context_object_name = "bpsubject_list"
    template_name = 'index.html'

    def get_context_data(self, **kwargs):
        context = super(BPCategoryList, self).get_context_data(**kwargs)
        context['bpobjecttype_list'] = BPObjectType.objects.all()
        context['bptechnotype_list'] = BPTechnoType.objects.all()
        context['bioprotocol_list'] = Bioprotocol.objects.all()

        return context 

然后将该视图挂钩到我的网址:

urlpatterns = patterns('',
                      url(r'^index/', BPCategoryList.as_view()),
)

index.html的模板如下:

注意:在MPTT模型中,它会自动生成一个“Level”字段,指示树结构中对象的级别,并且我在类别名称上分配了“技术类型”/“对象类型”/“主题”等级0.

<div id="container">
            <div id="sidebar">
                <div class="mainNavs">
                    <div class="menu_box">
                    {% for bptechnotype in bptechnotype_list %} 
                    {% if bptechnotype.level = 0 %} <!-- The Level 0 of the MPTT Model  -->
                    <div class="menu_main">
                        <h2>{{ bptechnotype.name }}</h2>
                    </div>
                    <div class="menu_sub dn">
                    {% elif bptechnotype.level = 1 %}
                        <dl class="reset">
                            <dt><a href="/bptechnotype/{{ bptechnotype.name }}">{{ bptechnotype.name }}</a></dt>
                            <dd>
                                {% for children in bptechnotype.get_children %}
                                <a href="/bptechnotype/{{ children.name }}">{{ children.name }}</a>
                                {% endfor %}
                            </dd>
                        </dl>
                    {% endif %}
                    {% endfor %}
                    </div>
                    </div>
                    <div class="menu_box">
                    {% for bpobjecttype in bpobjecttype_list %}
                    {% if bpobjecttype.level = 0 %}
                    <div class="menu_main">
                        <h2>{{ bpobjecttype.name }}</h2>

                    </div>
                    <div class="menu_sub dn">
                    {% elif bpobjecttype.level = 1 %}
                        <dl class="reset">
                            <dt><a href="/bpobjecttype/{{ bpobjecttype.name }}">{{ bpobjecttype.name }}</a></dt>
                            <dd>
                                {% for children in bpobjecttype.get_children %}
                                <a href="/bpobjecttype/{{ children.name }}">{{ children.name }}</a>
                                {% endfor %}
                            </dd>
                        </dl>
                    {% endif %}
                    {% endfor %}
                    </div>
                    </div>
                    <div class="menu_box">
                    {% for bpsubject in bpsubject_list %}
                    {% if bpsubject.level = 0 %}
                    <div class="menu_main">
                        <h2>{{ bpsubject.name }}</h2>
                    </div>
                    <div class="menu_sub dn">
                    {% elif bpsubject.level = 1 %}
                        <dl class="reset">
                            <dt><a href="/bpsubject/{{ bpsubject.name }}">{{ bpsubject.name }}</a></dt>
                            <dd>
                                {% for children in bpsubject.get_children %}
                                <a href="/bpsubject/{{ children.name }}">{{ children.name }}</a>
                                {% endfor %}
                            </dd>
                        </dl>
                    {% endif %}
                    {% endfor %}
                    </div>
                    </div>
                </div> 

上面的脚本工作得很好。但是,每次只能使用一种类型的过滤器来获取相应的协议。但是在得到上述结果后我想做更多。我希望下一页使用ListView,使用户能够缩小他们的选择范围,例如,只有一些具有某些特定主题的此对象类型的协议。因此,我想基于这三个类别构建过滤器。我在views.py中添加了三个ListView,在这里我只选择其中一个(BPTechnoTypeBioprotocolList)来解决问题:

class BPTechnoTypeBioprotocolList(ListView): 
    template_name = 'bioprotocol_list.html'

    def get_queryset(self):
        self.technotype = get_object_or_404(BPTechnoType, name=self.args[0])
        bptechnotype_list = Bioprotocol.objects.filter(TechnoType__lft__gte=self.technotype.lft, TechnoType__rght__lte=self.technotype.rght)
        return bptechnotype_list

    def get_context_data(self, **kwargs):
        context = super(BPTechnoTypeBioprotocolList, self).get_context_data(**kwargs)
        bpobjecttype_list = []
        bptechnotype_list = []
        bpsubject_list = []
        for item in self.get_queryset():
            bpobjecttype = BPObjectType.objects.filter(bioprotocol__id=item.id)
            bpsubject = BPSubject.objects.filter(bioprotocol__id=item.id)
            bptechnotype = BPTechnoType.objects.filter(bioprotocol__id=item.id)
            bpobjecttype_list += bpobjecttype
            bpsubject_list += bpsubject
            bptechnotype_list += bptechnotype
        objecttypecount = Counter(bpobjecttype_list).most_common()
        technotypecount = Counter(bptechnotype_list).most_common()
        subjectcount = Counter(bpsubject_list).most_common()            
        # Add in the subject
        context['bpobjecttype_list'] = objecttypecount
        context['bptechnotype_list'] = technotypecount
        context['bpsubject_list'] = subjectcount
        context['bptechnotype'] = self.technotype
        return context

并在我的urls.py中添加:

url(r'^bptechnotype/([\w-]+)/$', BPTechnoTypeBioprotocolList.as_view()),

bioprotocol_list.html的模板是:

<div class="sidebar">
                <div id="options" class="greybg">
                    <dl>
                        <dt>
                            "Object Type"
                        </dt>
                        <dd>
                            {% for objecttype in bpobjecttype_list %}
                            <div class="option">
                                <label>
                                <input type="checkbox" checked="" value="">{{ objecttype.0 }}</label> ({{ objecttype.1 }})
                            </div>
                            {% endfor %}
                        </dd>
                    </dl>
                    <dl>
                        <dt>
                            "Technology Type"
                        </dt>
                        <dd>
                            {% for technotype in bptechnotype_list %}
                            <div class="option">
                                <label>
                                <input type="checkbox" checked="" value="">{{ technotype.0 }}</label> ({{ technotype.1 }})
                            </div>
                            {% endfor %}
                        </dd>
                    </dl>
                    <dl>
                        <dt>
                            "Subject"
                        </dt>
                        <dd>
                            {% for subject in bpsubject_list %}
                            <div class="option">
                                <label>
                                <input type="checkbox" checked="" value="">{{ subject.0 }}</label> ({{ subject.1 }})
                            </div>
                            {% endfor %}
                        </dd>
                    </dl>
                    <button type="button" id="selectall">Select All</button>
                    <button type="button" id="cancelall">Cancel</button>
                    <button type="button" id="applyfilter">Filter</button>
                    <script type="text/javascript">
                        $(document).ready(function(){
                            $("#selectall").click(function(){
                                $("input").prop('checked', true)
                            });
                            $("#cancelall").click(function(){
                                $("input").prop('checked',false)
                            });
                            $("#applyfilter").click(function(){
                                SHOULD DO SOMETHING AND SEND THE QUERYSET TO THE LISTVIEW
                                });
                            });
                        })
                    </script>   
                </div>
            </div>

主要思想是应用jQuery函数($(“#applyfilter”)。click(function(){})遍历每个复选框输入,并获取所有选中的过滤器并将请求发送到ListView并更改get_queryset()

脚本必须包含一些重复的代码。我期待一些简洁的方法,在一个页面上使用这三个类别的过滤器制作动态的对象列表。任何想法都赞赏。非常感谢你!

1 个答案:

答案 0 :(得分:0)

我通过将代码添加到

来自行修复
function getvalue(){
                            var objectchk = [];
                            var technochk = [];
                            var subjectchk = [];

                            $("input[name='objecttype']:checked").each(function(){
                                objectchk.push($(this).val());
                            });

                            $("input[name='technotype']:checked").each(function(){
                                technochk.push($(this).val());
                            });

                            $("input[name='subject']:checked").each(function(){
                                subjectchk.push($(this).val());
                            });

                            var dict = {
                                'ObjectType':objectchk, 'TechnoType':technochk, 'Subject':subjectchk
                            };

                            var params = $.param(dict);

                            $.ajax({
                                type: "GET",
                                data: {'ObjectType':objectchk, 'TechnoType':technochk, 'Subject':subjectchk},
                            });

                            window.location = "?" + params
                        }