我的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) + ........
像这样。
请帮帮我。
答案 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()