如果每次更新url中的参数,则自动添加过滤器

时间:2017-04-17 15:27:53

标签: python django

我的Post模型有多个外键。

class Post(models.Model):
    category = models.ForeignKey(Category)
    location = models.ForeignKey(Location)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    title = models.CharField(max_length=255)
    text = models.CharField(max_length=255)

    objects = PostQuerySet.as_manager()

    def __str__(self):
        return self.title

class Category(models.Model):
    parent = models.ForeignKey('Category', related_name='children', null=True, blank=True)
    name = models.CharField(max_length=255)
    slug = models.SlugField()

    @property
    def dispatch(self):
        if not self.parent:
            return self
        else:
            return self.parent

    def __str__(self):
        return self.name

class Location(models.Model):
    parent = models.ForeignKey('Location', related_name='children', null=True, blank=True)
    name = models.CharField(max_length=255)

    @property
    def dispatch(self):
        if not self.parent:
            return self
        else:
            return self.parent

    def __str__(self):
        return self.name

class PostQuerySet(models.QuerySet):

    def filter_category(self, category):
        if not category.parent:
            return self.filter(category__in=category.children.all())
    else:
        return self.filter(category=category)

    def filter_location(self, location):
        if not location.parent:
            # first
            return self.filter(location__parent__in=location.children.all())
        else:
            if not location.dispatch.parent:
                # second
                return self.filter(location__in=location.children.all())
            else:
                # third
                return self.filter(location=location)

我有这样的过滤系统:

<p>[ Category ]</p>
<ul>
    {% if request.GET.category %}
        <li><a href="{% url_remove request 'category' %}">All Categories</a></li>
    {% endif %}

    {% if big_cat %}
        <li><a href="?{% url_replace request 'category' big_cat.pk %}">{{ big_cat.name }} | {{ big_cat.pk }}</a></li>
        {% for small_cat in big_cat.children.all %}
            <li>---<a href="?{% url_replace request 'category' small_cat.pk %}">{{ small_cat.name }} | {{ small_cat.pk }}</a></li>
        {% endfor %}
    {% else %}
        {% for big_cat in big_cats %}
            <li><a href="?{% url_replace request 'category' big_cat.pk %}">{{ big_cat.name }} | {{ big_cat.pk }}</a></li>
        {% endfor %}
    {% endif %}
</ul>

<p>[ Location ]</p>
<ul>
    {% if request.GET.location %}
        <li><a href="{% url_remove request 'location' %}">All Locations</a></li>
    {% endif %}
    {% if state %}
        <li><a href="?{% url_replace request 'location' state.pk %}">{{ state.name }} | {{ state.pk }}</a></li>
        {% if region %}
            <li>---<a href="?{% url_replace request 'location' region.pk %}">{{ region.name }} | {{ region.pk }}</a></li>
            {% for city in region.children.all %}
                <li>------<a href="?{% url_replace request 'location' city.pk %}">{{ city.name }} | {{ city.pk }}</a></li>
            {% endfor %}
        {% else %}
            {% for region in regions %}
                <li>---<a href="?{% url_replace request 'location' region.pk %}">{{ region.name }} | {{ region.pk }}</a></li>
            {% endfor %}
        {% endif %}
    {% else %}
        {% for state in states %}
            <li><a href="?{% url_replace request 'location' state.pk %}">{{ state.name }} | {{ state.pk }}</a></li>
        {% endfor %}
    {% endif %}
</ul>

views.py是:

def index(request):
    category_pk = request.GET.get('category')
    location_pk = request.GET.get('location')

    c = {'posts': Post.objects.all()}

    if location_pk:
        location = get_object_or_404(Location, pk=location_pk)
        if not location.parent and location.children.exists():
            c.update({
                'state': location.dispatch,
                'regions': location.children.all(),
        })
        elif location.parent and location.children.exists():
            c.update({
                'state': location.dispatch,
                'region': location,
        })
        elif location.parent and not location.children.exists():
            c.update({
                'state': location.dispatch.parent,
                'region': location.parent,
            })
    else:
        c.update({'states': Location.objects.filter(parent__isnull=True)})

    return render(request, 'classifieds/index.html', c)

如果我在views.py中编写代码,如:

Post.objects.filter_category(category).filter_location(location)

我可以获得与类别和位置相关的帖子。但如果我这样做,我需要这样做:

if category_pk and location_pk:
    category = get_object_or_404(Category, pk=category_pk)
    location = get_object_or_404(Location, pk=location_pk)
    posts = Post.objects.filter_category(category).filter_location(location)

elif category_pk:
    category = get_object_or_404(Category, pk=category_pk)
    posts = Post.objects.filter_category(category)

elif location_pk:
    location = get_object_or_404(Location, pk=location_pk)
    posts = Post.objects.filter_location(location)

else:
    posts = Post.objects.all()

这太复杂了。我想在未来添加类似价格的外键。因此,如果每次都更新url中的参数,我想知道自动添加过滤器的方法。

简单地说: 每次我在url中获取get参数或者更新如下:

?category=ooo&location=ooo

我想自动添加指定的过滤器:

Post.objects + filter(ooo=ooo) + filter(ooo=ooo) + ........
像这样。

请帮帮我。

2 个答案:

答案 0 :(得分:0)

这是你可以尝试的东西

import operator
from django.db.models import Q
q_expression = [Q(x) for x in request.GET.items()]
Post.objects.filter(reduce(operator.and_, q_expression))

答案 1 :(得分:0)

解决:

q = []
for x in request.GET.items():
    if x[0] == 'category':
        try:
            category = Category.objects.get(pk=x[1])
            if not category.parent:
                x = list(x)
                x[0] = 'category__parent'
                q.append(Q(tuple(x)))
            else:
                x = list(x)
                x[0] = 'category'
                q.append(Q(tuple(x)))
        except Category.DoesNotExist:
            pass
    if x[0] == 'location':
        try:
            location = Location.objects.get(pk=x[1])
            if not location.parent:
                x = list(x)
                x[0] = 'location__parent__parent'
                q.append(Q(tuple(x)))
            else:
                if not location.dispatch.parent:
                    x = list(x)
                    x[0] = 'location__parent'
                    q.append(Q(tuple(x)))
                else:
                    x = list(x)
                    x[0] = 'location'
                    q.append(Q(tuple(x)))
        except Location.DoesNotExist:
            pass

if len(q) > 0:
    posts = Post.objects.filter(reduce(operator.and_, q))
else:
    posts = Post.objects.all()