使用其他模型的对象过滤对象

时间:2016-11-23 15:00:13

标签: python django filter

我有父母,姓名和孩子模特:

models.py

class Parent(models.Model):
    title = models.CharField(max_length=250)
    address = models.CharField(max_length=250)


class Name(models.Model):
    title = models.CharField(max_length=250)


class Kid(models.Model):
    family = models.ForeignKey(Parent)
    name = models.ForeignKey(Name)
    age = models.IntegerField()
    city = models.CharField(max_length=250)

我有一个view函数,只有当与Parent相关的Kid对象都在字典中时才显示Parent对象:

views.py

def index(request):
    patterns = [
        {'name__title': 'samy', 'age__lt': 15, 'city': 'paris'},
        {'name__title': 'sally', 'age__gt': 20, 'city': 'london'}
    ]
    filter_q = reduce(operator.or_, map(lambda p: Q(**p), patterns))
    qs = Kid.objects.filter(filter_q).values_list('id', 'family_id')
    family_ids = set()
    child_ids = list()
    for child_id, family_id in qs:
        family_ids.add(family_id)
        child_ids.append(child_id)
    incomplete_family_ids = set(Kid.objects.exclude(id__in=child_ids).filter(family_id__in=family_ids).values_list('family_id', flat=True).distinct())
    complete_family_ids = family_ids - incomplete_family_ids
    parents = Parent.objects.filter(id__in=complete_family_ids)
    template = 'index.html'
    context = {'parents': parents}
    return render(request, template, context)

如果我想用模型对象替换模式字典,例如:

,该怎么办?
class Pattern(models.Model):
    title = models.CharField(max_length=250)


class PatternItems(models.Model):
    name = models.ForeignKey(Name)
    age = models.integer()
    city = models.CharField(max_length=250)
    pattern = models.ForeignKey(Pattern) 

所以不是字典。我想知道是否有可能从Pattern模型中选择一个模式来显示Parent对象,如果它所有相关的Kid对象都使用Pattern对象在PatternItems中。

整个想法是让过滤器动态化,并允许用户自己制作过滤器。

帮助?

2 个答案:

答案 0 :(得分:3)

您可以替换这段代码:

patterns = [
    {'name__title': 'samy', 'age__lt': 15, 'city': 'paris'},
    {'name__title': 'sally', 'age__gt': 20, 'city': 'london'}
]
filter_q = reduce(operator.or_, map(lambda p: Q(**p), patterns))

使用循环添加任意数量的过滤器:

# init patterns as a list of PatternItems
patterns = [ PatternItem(name=Name(title='samy'), age=15, city='paris'),
             PatternItem(name=Name(title='sally'), age=20, city='london'),
           ]
# iterate through the list normally
filters = []
for pt_item in patterns:
    filters.append(Q(name__title=pt_item.name.title) & 
                    Q(age__lt=pt_item.age) & Q(city=pt_item.city))

filter_q = filters[0]
for f in filters[1:]:
    filter_q |= f

获取patterns的另一种方法是评估QuerySet,例如使用filter()

# any_column__gte and value here are just examples
patterns = PatternItem.objects.filter(any_column__gte=value)
# iterate through the patterns using .all()
filters = []
for pt_item in patterns.all():
    ...

此方法的唯一问题是您必须对列表中的每个age__lt使用相同的比较(即PatternItem)。

请注意:我使用循环而不是reduce()函数,因为它在Python 3中不存在。

答案 1 :(得分:0)

所以这个问题的答案可能并不清楚。 @Paolo Stefan代码非常接近我的需要。

<强> view.py

patterns = PatternItems.objects.filter(pattern__title='adults')
filters = []
for pt_item in patterns.all():
    filters.append(Q(name__title=pt_item.name.title) &
                   Q(age__lt=pt_item.age) & Q(city=pt_item.city))

filter_q = filters[0]
for f in filters[1:]:
    filter_q |= f
qs = Kid.objects.filter(filter_q).values_list('id', 'family_id')
family_ids = set()
child_ids = list()
for child_id, family_id in qs:
    family_ids.add(family_id)
    child_ids.append(child_id)
incomplete_family_ids = set(Kid.objects.exclude(id__in=child_ids).filter(family_id__in=family_ids).values_list('family_id', flat=True).distinct())
complete_family_ids = family_ids - incomplete_family_ids
parents = Parent.objects.filter(id__in=complete_family_ids)
template = 'index.html'
context = {'parents': parents}
return render(request, template, context)

唯一的区别是:     patterns = PatternItems.objects.filter(pattern__title ='adults')

使用“成人”所需的模式过滤模式项目。